You are on page 1of 60

DEVELOPING

C/C++
ORACLE APPLICATIONS
WITH

How to
easily and efficiently program
Oracle effective applications
in C/C++

Written by Vincent Rogier


Developing C/C++ Oracle applications with OCILIB 2

DEVELOPING
C/C++
ORACLE APPLICATIONS
WITH
OCILIB

Copyright (C) Vincent Rogier

Permission is granted to copy, distribute and/or modify this document


under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled
“GNU Free Documentation License".

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 3

Contents

1. Introduction ......................................................................................................................... 5

Revision ................................................................................................................................. 5
Introduction ............................................................................................................................ 5
Complexity of OCI ................................................................................................................... 5
Why OCILIB? .......................................................................................................................... 6
Features ................................................................................................................................. 6
Documentation........................................................................................................................ 6

2. Installation ........................................................................................................................... 7

Requirements ......................................................................................................................... 7
Compatibilities ........................................................................................................................ 7
Installing OCILIB on Unix (Unix/Linux/Mac) ................................................................................ 7
Installing on Microsoft Windows ................................................................................................ 8
Oracle Instant Client Support .................................................................................................... 8
Project Configuration ............................................................................................................... 9
Charset support .................................................................................................................... 10
Unicode support .................................................................................................................... 11
Oracle Supported datatypes .................................................................................................... 11
OCILIB datatypes .................................................................................................................. 12

3. Connecting to Oracle .......................................................................................................... 13

Initializing OCILIB ................................................................................................................. 13


Creating a connection ............................................................................................................ 13
Using transactions ................................................................................................................. 14

4. Error handling .................................................................................................................... 15

Global error handling ............................................................................................................. 15


Contextual thread error handling ............................................................................................. 16

5. Executing SQL statements .................................................................................................. 17

SQL Statements .................................................................................................................... 17


Binding Variables................................................................................................................... 17
Retrieving the result of a query ............................................................................................... 19
Resultset metadata information ............................................................................................... 20
Implicit conversions ............................................................................................................... 21
Scrollable statements ............................................................................................................ 22
PL/SQL blocks ....................................................................................................................... 23
Support for SQL RETURNING clause ......................................................................................... 24
Statements extra control ........................................................................................................ 25

6. Bulk Operations .................................................................................................................. 26

Oracle Array interface ............................................................................................................ 26


Example ............................................................................................................................... 27

7. Using Larges Objects .......................................................................................................... 28

Internal Objects (LOBs) .......................................................................................................... 28


External Objects (FILEs) ......................................................................................................... 30
Long Objects......................................................................................................................... 32

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 4

8. Using dates and timestamps .............................................................................................. 34

Date handles ........................................................................................................................ 34


Timestamp handles ............................................................................................................... 34
Interval handles .................................................................................................................... 35

9. Using Oracle objects (U.D.T. / Named Types) .................................................................... 36

Autonomous Instances ........................................................................................................... 37


Selecting objects ................................................................................................................... 37

10. Using Oracle Collections ..................................................................................................... 38

Collections types ................................................................................................................... 38


Example ............................................................................................................................... 38

11. Loading data with Direct Path mode ................................................................................... 40

Oracle Direct Path Loading...................................................................................................... 40


Example ............................................................................................................................... 41

12. Advanced features .............................................................................................................. 42

Describing tables in a schema ................................................................................................. 42


Functions '"All In One" ........................................................................................................... 42
Optimizing performances ........................................................................................................ 45
Using OCILIB hash tables API ................................................................................................. 45
Using OCILIB thread API ........................................................................................................ 46
Remote database startup/shutdown ......................................................................................... 48
Database change notifications ................................................................................................. 48
Going deeper in OCI: direct use of OCI handles ......................................................................... 52

13. Annexes ............................................................................................................................. 53

GNU Free Documentation License ............................................................................................ 53

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 5

1. Introduction

Revision

List of revisions of the document:

• 07/01/2008 - Released (version 1.5.1)


• 13/02/2008 - Updated (version 2.0.0)
• 21/02/2008 - Updated (added “optimizing performances”)
• 07/03/2008 - Updated (corrected linker options)
• 20/03/2008 - Updated (corrected “Features”)
• 29/03/2008 - Updated (various fixes)
• 01/04/2008 - Updated (version 2.3.0)
• 24/04/2008 - Updated (version 2.4.0 + various modifications)
• 21/07/2008 - Updated (version 2.5.0 + various modifications)
• 13/10/2008 - Updated (version 3.0.0: major update)
• 28/01/2009 - Updated (version 3.1.0)
• 20/04/2009 - Updated (version 3.2.0)
• 15/01/2010 - Rewritten (full rewrite, version 3.5.0, translation to English, added GNU FDL license)

Introduction

OCILIB is an open source and cross platform Oracle library that delivers really efficient and reliable access
to Oracle databases.

The library OCILIB:

• Provides a rich and easy API


• Runs on all platforms Oracle
• Is written in pure ISO C and has native ISO C Unicode support
• Enables high productivity
• Encapsulates OCI (Oracle Call Interface)
• Is the most complete OCI wrapper available

Complexity of OCI

Oracle Call Interface (OCI) is an API provided by Oracle that allows developers to create applications
using low C/C++ calls to access to Oracle databases. OCI controls all aspects of running SQL statements
while supporting data types, calling conventions, syntax and semantics of C, C++ languages.

OCI is a very powerful API (this is the lowest level API provided by Oracle) and used by many applications
and tools (starting with SQL*Plus, SQL*Loader and all Oracle products) but also very complex and heavy
to use...

For example, connecting to an Oracle database requires at least almost 100 lines of code!
In addition, most functions of OCI often require a list of arguments fairly consistent (like a dozen
parameters) and complex (almost exclusive manipulation of pointers, pointers of pointers, etc. ...).

Thus, an OCI application is often difficult to code, read and maintain!

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 6

Why OCILIB?

OCILIB encapsulates OCI in order to provide optimal reusability of code. It is free (open source - LGPL
license), rich (about 550 simple functions) and its source code is platform-independent (MS Windows,
HP/UX, AIX, Solaris, Linux And Mac).

OCILIB really boosts productivity of C/C++ database oriented development with its JDBC like API.

OCILIB can combine the performance of C/C++ by proposing a pragmatic interface, easy to use, while
maintaining richness in functionality. OCILIB is one of the few C/C++ based OCI libraries that provides
complete Unicode support. An OCILIB application can be compiled either natively in ANSI or Unicode.

Finally, OCILIB source code is 100% ISO C90 (and C99 for full Unicode support) and thus extremely
portable! OCILIB does not require an Oracle client to develop Oracle application. Indeed, an application
using OCILIB can link Oracle libraries at compilation time (static or dynamic linkage) or at runtime if the
target OS supports dynamic loading of modules. OCILIB works on all platforms supported by Oracle
(Microsoft Windows, Linux, UNIX, Mac ...).

Currently, OCILIB is widely used in:

• Banking applications
• Industrial applications
• Generic databases frameworks as internal Oracle layer

Features

Here is a list of key features at the last revision of the tutorial (v3.5.0 released on 2009-12-21):

• Full ANSI and Unicode support on all platforms


• Built-in error handling (global and thread context)
• Support for ALL Oracle SQL and PL/SQL datatypes (scalars, objects, refs, collections, ..)
• Support for non scalar datatype with trough library objects
• Binding array Interface for fast and massive bulk operations
• Reusable and scrollable statements
• Connection Pooling
• Global Transactions
• Full PL/SQL support (blocks, cursors, Index by Tables and Nested tables)
• Returning DML feature support
• Direct Path loading
• Runtime loading
• Remote Instances Startup/Shutdown
• Oracle Database Change notification / Continuous Query Notification
• Oracle warnings support
• Describe database schema objects
• Hash tables API
• Portable Threads and mutexes API

Documentation

• Online documentation : http://www.ocilib.net/doc/html/


• The documentation is also included in the distributions of OCILIB

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 7

2. Installation

Requirements

• An Operating system supported by Oracle (MS Windows, Unixes, Mac, …)


• An Oracle client (regular or Instant) (note that the client is not required for compilation)

Compatibilities

The following platforms have been validated (compilation, installation, build and execution):

Microsoft Windows
Linux
Solaris
HP/UX
AIX
Mac OS X

Other platforms supported by Oracle (for example, z/OS) have not been officially "validated", but given
the platforms already validated, porting OCILIB to these platforms should not be a big deal!

The following compilers have been validated:

Microsoft Compilers (VC++, VS200X)


GCC and MinGW
IBM XLC
Proprietary CC (HP, AIX ...)
LabView

The following versions of Oracle (clients and servers) have been validated:

Oracle 8i (> 8.0)


Oracle 9i (all)
Oracle 10g (R1 and R2)
Oracle 11g (R1)

Installing OCILIB on Unix (Unix/Linux/Mac)

OCILIB uses GNU tools for deployment and installation:

Unpack the current archive (ocilib-xyz-gnu.tar.gz)


$ cd ocilib-x.y.z
$ ./configure
$ ./make
$ ./make install (needs user root)

Check the dynamic libraries path environment variable (LD_LIBRARY_PATH, LD_PATH...) and make sure
that the Oracle and OCILIB shared libraries locations are included.

Typically, just add theses to your .profile file. Example:

$ Export LD_LIBRARY_PATH =$LD_LIBRARY_PATH:$ORACLE_HOME/lib:/usr/local/lib

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 8

OCILIB supports 6 additional installation options:

--with-oracle-import = (linkage | runtime)


--with-oracle-charset = (ANSI | Unicode | Mixed)
--with-oracle-home = (oracle home)
--with-oracle-headers-path = (location of OCI headers files)
--with-oracle-lib-path = (location of OCI shared libraries)
--with-custom-loader = (linker flag telling the target linker which loader to use when loading Oracle
shared libraries dynamically at runtime. This option must be provided if the
platform does not use the default loader flag '-ldl') and if the --with-
oracle-import is set to 'runtime')

Note: If the compiler is GCC, the default GNU tools (autoconf and automake) use the flags '-g-O2'. This
therefore adds debugging in formations to the generated libraries:

• Until the 2.xx versions, this could increase the final size of the library 50% on average (total size
300 Kb on Linux)
• From version 3.0.0 (the source code has been split into several files, the increase may be 300%!
(650 Kb on Linux)
• The strip command can remove debugging symbols from the OCILIB shared library (final size 150
Kb)

Installing on Microsoft Windows

On Microsoft Windows, 32bits and 64bits (x86) DLLs are provided and can be easily recompiled.

Unpack the current archive (ocilib-xyz-windows.zip)

Copy ocilib\include\ocilib.h : to a folder listed in the compiler headers folders


Copy ocilib\lib32 |64\ocilib [x].Lib : to a folder listed in the linker libraries folders
Copy ocilib\lib32|64\ocilib [x]. Dll : to a folder included in the PATH environment variable

[x] is the compiled version of OCILIB ('a' -> ANSI, 'w' -> Unicode, 'm' -> Mixed)

Oracle Instant Client Support

On Microsoft Windows, there is no difference between using a regular Oracle client and an Instant Client
with OCILIB.

On Unix-like systems, the Instant Client is divided in different packages. Public headers and shared
libraries are not part of the same package.

So, you must provide the following options to the configure command:

--with-oracle-headers-path : location the public header files


--with-oracle-lib-path : location the oracle shared libraries

If your instant client package containing the shared libraries does not have a symbolic link
'libclntsh.$(shared lib extension)' to the fully qualified shared lib real name, you must create it:

$ ln-s $ORALIBPATH/libclntsh.so.10.1 $ ORALIBPATH/libclntsh.so

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 9

Project Configuration

To use OCILIB in a project, include the file “ocilib.h”

Some options must be defined before including this header.

Oracle linkage mode:

- OCI_IMPORT_LINKAGE: linking Oracle libraries (shared or static) at compilation time


- OCI_IMPORT_RUNTIME: loading dynamically Oracle libraries at runtime

Oracle charset mode:

- OCI_CHARSET_ANSI : all strings are in ANSI


- OCI_CHARSET_UNICODE : all strings are Unicode (versions of Oracle> = 9i)
- OCI_CHARSET_MIXED : SQL statements + metadata are in ANSI, user data and resultset data in Unicode

Calling Convention (MS Windows only):

- OCI_API: Undefined
- OCI_API: __sdtcall to use precompiled dlls

Windows

For example, to use the ANSI built of OCILIB using the supplied DLLs with MS Visual Studio:

- Create a new project


- Include "ocilib.h"
- Set OCI_API = __sdtcall in the project preprocessor options

If all OCILIB import libraries builds (ocilib[x].lib) are accessible to the linker, then you must specify which
one to use with:

#pragma comment (lib, "ocilib[x].lib")

Note: from version 3.2.0, static libraries are also provided for the Windows port of GCC: libociliba.a,
libocilibm.a and libocilibw.a

Unixes

For example, to use the ANSI built of OCILIB linking Oracle shared libraries are compile time (let’s
suppose that the variable $USER_LIBS points to the parent directory where OCILIB is installed, default is
usr/local/):

- Include "ocilib.h"
- Add compile options the makefile
o -I$USER_LIBS/include (for header ocilib.h)
o -DOCI_IMPORT_LINKAGE -DOCI_CHARSET_ANSI (OCILIB options)
- Add linkage options to the makefile
o -L/$ORACLE_HOME/lib (for Oracle shared lib)
o -L$USER_LIBS/lib -locilib (for OCILIB shared lib)

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 10

Charset support

OCILIB supports ANSI and Unicode charsets

OCILIB uses char/wchar_t strings for public interface and internal storage.

Oracle started a real Unicode support with Oracle8i but only for user data. All SQL and PL/SQ/ statements,
metadata string, database objects names, etc ... were still only supported in ANSI.

With Oracle 9i, Oracle provides a full Unicode support.

So depending on the compile time Oracle library or the runtime loaded library, the Unicode support
differs. OCILIB supports:

ANSI (char)
Unicode (wchar_t)
Mixed charset: ANSI for metadata, Unicode for user data

OCILIB uses two types of strings:

mtext: for metadata, SQL strings, object attributes.


dtext: for input binds and output data

mtext and dtext are declared as defines around char and wchar_t depending on the charset option

Text macros :

MT(): 'meta text' -> meta data and strings passed to OCI calls
DT(): 'data text' -> user input/output data

Summary :

Element OCI_CHARSET_ANSI OCI_CHARSET_UNICODE OCI_CHARSET_MIXED


Dtext char wchar_t wchar_t
DT(x) x L ## x x
Dtext char wchar_t char
MT(x) X L ## x x

Additional macros:

Theses macros are based on the model:


* mtsxxx() for mtext * typed strings
* dtsxxx() for dtext * typed strings
xxx is the standard C library string function name without the character type prefix (str/wcs).
List of available macros:

* mtsdup, dtsdup
* mtscpy, dtscpy
* mtsncpy, dtsncpy
* mtscat, dtscat
* mtsncat, dtsncat
* mtslen, dtslen
* mtscmp, dtscmp
* mtscasecmp, dtscasecmp
* mtsprintf, dtsprintf
* mtstol, dtstol

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 11

Unicode support

Well, ISO C:

• Doesn’t know anything about Unicode.


• Makes wide characters support tricky because the size of a wide character is not defined and is
freely adaptable by implementations.

OCILIB fully supports Unicode on all platforms around the C data type wchar_t (UTF16/UTF32 between
platforms).

OCILIB, for Unicode builds, initialize OCI in UTF16 Unicode mode. Oracle implements this mode with a 2
bytes (fixed length) UTF16 encoding.

So, on systems implementing wchar_t as 2 bytes based UTF16 (e.g. Ms Windows), input strings are
directly passed to Oracle and taken back from it.

On other systems (most of the unixes) that use UTF32 as encoding (4 bytes based wchar_t), OCILIB
uses:

* Temporary buffers to pass string to OCI for metadata strings


* Buffer expansion from UTF16 to UTF32 for user data string:
o allocation based on sizeof(wchar_t)
o data filling based on sizeof(short) -> (UTF16 2 bytes)
o data expansion to sizeof(wchar_t).

The buffer expansion is done in place and has the advantage of not requiring extra buffer. That reduces
the cost of the Unicode/ISO C handling overhead on Unixes.

Oracle Supported datatypes

OCILIB supports all data types provided by Oracle. List of supported types:

• All scalar types (strings, numeric...): CHAR / NCHAR, VARCHAR2/NVARCHAR2, NUMBER, FLOAT...
• Types binary: RAW, LONG RAW, VARRAW...
• Large Objects (LOBs and Files): BLOB, CLOB, NCLOB, BFILE, CFILE
• Types LONG: LONG VAR LONG, LONG RAW ...
• Date, Timestamps and Intervals: DATE, TIMESTAMP (all), INTERVAL (all)
• PL / SQL types: Ref cursors, PL / SQL tables (tables) and PL / SQL Nested Tables
• Objects (Named Types): user types and type systems
• Objects References: REF Type
• SQL Collections: VARRAY and Nested Tables
• ROWID and UROWID

All these types can be binded to statements or be retrieved from a select statement.

Oracle TYPE OCILIB Type


Strings : CHAR/NCHAR, VARCHAR2/NVARCHAR2, dtext * (char * or wchar_t * depending on
.... build)
Numbers : INT, NUMBER, ... shorts, ints, big ints (signed/unsigned)
REAL : FLOAT, REAL, NUMBER(X,Y), .... double
RAW void *
LONG, LONG RAW, VARRAW, .. OCI_Long
BLOB / CLOB / NCLOB OCI_Lob

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 12

DATE OCI_Date
TIMESTAMP, TIMESTAMP_TZ, TIMESTAMP_LTZ OCI_Timestamp
INTERVAL, INTERVAL_YM, INTERVAL_DS OCI_Interval
PL/SQL Ref Cursors OCI_Statement
Tableaux C de types scalaires ou objets
PL/SQL Tables
OCILIB
PL/SQL Nested Tables OCI_Statement
Objects (User Types) OCI_Object
Objects References (REF) OCI_Ref
Collections (Varrays et Nested Tables) OCI_Coll et OCI_Elem
dtext * (char * or wchar_t * depending on
ROWID et UROWID
build)

OCILIB datatypes

Here are the OCILIB data types with brief descriptions:

OCI_Bind Internal bind representation


OCI_Coll Oracle Collections (VARRAYs and Nested Tables) representation
OCI_Column Oracle SQL Column and Type member representation
OCI_Connection Oracle physical connection
OCI_ConnPool Oracle Connection Pool
OCI_Date Oracle internal date representation
OCI_DirPath OCILIB encapsulation of OCI Direct Path handle
OCI_Elem Oracle Collection item representation
OCI_Error Encapsulates an Oracle or OCILIB exception
OCI_Event OCILIB encapsulation of Oracle DCN event
OCI_File Oracle External Large objects:
OCI_HashEntry Hash table entry
OCI_HashTable OCILIB implementation of hash tables
OCI_HashValue Hash table entry value
OCI_Interval Oracle internal interval representation
OCI_Iter Oracle Collection iterator representation
OCI_Lob Oracle Internal Large objects:
OCI_Long Oracle Long datatype
OCI_Mutex OCILIB encapsulation of OCI mutexes
OCI_Object Oracle Named types representation
OCI_Ref Oracle REF type representation
OCI_Resultset Collection of output columns from a select statement
OCI_Statement Oracle SQL or PL/SQL statement
OCI_Subscription OCILIB encapsulation of Oracle DCN notification
OCI_Thread OCILIB encapsulation of OCI Threads
OCI_Timestamp Oracle internal timestamp representation
OCI_Transaction Oracle Transaction
OCI_TypeInfo Type info metadata handle
OCI_Variant Internal Variant type based on union C type
OCI_XID Global transaction identifier

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 13

3. Connecting to Oracle

Initializing OCILIB

First of all, OCILIB must be initialized. This requires a call to OCI_Initilalize() before any other calls.

This function initializes the library and takes as parameters:

• [Optional] a global error handler procedure


• [Optional] Oracle shared library path (only if OCILIB is built with OCI_IMPORT_RUNTIME)
• The library initialization mode

The possible values for the initialization mode are:

• OCI_ENV_DEFAULT : default mode (not thread safe)


• OCI_ENV_THREADED : support for multithreading (thread safe)
• OCI_ENV_CONTEXT : Enabling context error handling per thread

Any attempt to create any OCILIB objects before initializing OCILIB generates an error that can be
recovered by OCI_GetLastError() if OCI_ENV_CONTEXT is set.

#include "ocilib.h"

int main()
{
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
/* ... application code here ... */
OCI_Cleanup();

return EXIT_SUCCESS;
}

At the end of application, a call to OCI_Cleanup() is required to:

• Deallocate specifics objects not explicitly released by the program (connections, connection pools,
statements, type info objects, thread keys)
• Unload the Oracle shared library (only if OCILIB is built with OCI_IMPORT_RUNTIME)

Creating a connection

Connecting to an Oracle database is done by OCI_ConnectionCreate() that takes as parameters:

• Oracle connection string (Service name, full TNS connection string or an easy connect string)
• Oracle user
• Oracle user password
• The session mode

The possible values for the session mode are:

• OCI_SESSION_DEFAULT : default mode


• OCI_SESSION_SYSDBA : Oracle SYSDBA mode
• OCI_SESSION_SYSOPER : Oracle SYSOPER mode

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 14

This function connects to the server, creates a session and starts a transaction.
If successful, it returns a connection handle and the application can immediately execute SQL statements.

#include "ocilib.h"

int main(void)
{
OCI_Connection *cn;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);
if (cn != NULL)
{
printf(OCI_GetVersionServer(cn));
printf("Server major version : %i\n", OCI_GetServerMajorVersion(cn));
printf("Server minor version : %i\n", OCI_GetServerMinorVersion(cn));
printf("Server revision version : %i\n", OCI_GetServerRevisionVersion(cn));
printf("Connection version : %i\n", OCI_GetVersionConnection(cn));
/* ... application code here ... */
OCI_ConnectionFree(cn);
}

OCI_Cleanup();
return EXIT_SUCCESS;
}

To close the connection to the server, you need to free the connection object with OCI_ConnectionFree().

Using transactions

OCILIB supports local and global Oracle transactions.

Local transactions are implicit within connection objects and there is no specific call or programming step
for using it.

By default, once the application has connected to Oracle, a local transaction is created. Any modification
(insert, update, delete) is not visible to other sessions until the application explicitly commits the changes
using OCI_Commit().

If the application does not want to validate changes made onto the database since the last commit (or
connection if no commit done yet), it must call OCI_Rollback().

Note that OCILIB allows the application to auto commit changes after every SQL statement execution, so
no call to OCI_Commit() is required. To turn on/off(default) this mode, use OCI_SetAutoCommit().

Global transactions are optional and are designed for distributed or global transaction environments.

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 15

4. Error handling

OCILIB provides two mechanisms for error handling:

• Global error handling through callbacks.


• Contextual thread error handling

Exceptions are raised:

• On Oracle OCI API call error


• On Oracle SQL statement error
• On Internal OCILIB error (type checking, memory allocations ...)
• On Oracle warnings (OCI API or from SQL) from v3.5.0 if warnings are enabled

The two mechanisms to handle errors are not exclusive and can be mixed. Thread contextual error is also
available for single thread based applications

Oracle warnings are raised through the OCI_Error API. Such error handles have their error type property
set to OCI_ERR_WARNING.

Warning handing is disabled by default. To activate/deactivate this feature, use OCI_EnableWarnings().

Global error handling

When an exception is raised, OCILIB calls the error handler provided by the application. The prototype of
the callback to provide is:

typedef void (*POCI_ERROR) (OCI_Error *err);

A handle to an object OCI_Error is then supplied to the function. Exception properties are accessible
through a set of functions.

#include "ocilib.h"
void err_handler(OCI_Error *err)
{
printf("Error ORA-%05i - msg : %s\n", OCI_ErrorGetOCICode(err), OCI_ErrorGetString(err));
}

int main()
{
OCI_Connection *cn;
if (!OCI_Initialize(err_handler, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("wrong_db", "wrong_usr", "wrong_pwd",
OCI_SESSION_DEFAULT);
/* ... application code here ... */
OCI_Cleanup();
return EXIT_SUCCESS;
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 16

Contextual thread error handling

This mode permits retrieving the last error that occurred in the current thread (which may be the main
thread of the application).

In order to use the thread contextual error handling, you must call OCI_Initialize() with the flag
OCI_ENV_CONTEXT. When activated, error handles are stored per thread and the last error that occurred
within a thread can be retrieved with OCI_GetLastError()

Note that any successful OCILIB call clears the last error.

#include "ocilib.h"
int main()
{
OCI_Connection *cn;

if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT | OCI_ENV_CONTEXT))


return EXIT_FAILURE;

cn = OCI_ConnectionCreate("wrong_db", "wrong_usr", "wrong_pwd", OCI_SESSION_DEFAULT);


if (cn == NULL)
{
OCI_Error *err = OCI_GetLastError();
printf("errcode %d, errmsg %s", OCI_ErrorGetOCICode(err), OCI_ErrorGetString(err));
}
OCI_Cleanup();
return EXIT_SUCCESS;
}

Note that OCI_GetLastError() works like the MS Windows Win32 GetLastError() function.

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 17

5. Executing SQL statements

SQL Statements

To execute SQL commands on the database, you must create a SQL statement object using the function
OCI_CreateStatement().

Once this object is created, it is possible to execute any type of SQL or PL/SQL statement using
OCI_ExecuteStmt().

OCI_Connection *cn;
OCI_Statement *st;
/* ... */
st = OCI_StatementCreate(cn);
OCI_ExecuteStmt(st, "delete from my_table where code is null");
printf("%d row deleted", OCI_GetAffectedRows(st));
OCI_Commit(cn);

OCI_StatementFree(st);
/* ... */

OCI_ExecuteStmt() prepares and executes the given SQL statement and OCI_GetAffectedRows() retrieves
the number of deleted rows in the table.

To release a statement and its associated resources (resultset ...) when it is not more needed, call
OCI_StatementFree().

Note that an OCI_Statement object can be reused to run as many SQL statements as necessary.

Binding Variables

OCILIB supports OCI data binding APIs

It is therefore possible to link host user variables to SQL queries by providing their address statement.
Then every time the statement is executed, it uses the current values at the binded addresses.

Programs variables can be binded to an Oracle SQL PL/SQL statement in order to:

• Provide input data for SQL statement


• Provide input/output data for PL/SQL blocks

OCILIB provides a set of binding functions to use with:

• Basic datatypes: string (char/wchar_t *), int, double, raw


• Object datatypes: lobs, files, longs, dates, cursors, statements, timestamps, intervals, objects

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 18

To use binding:

• Prepare a statement with OCI_Prepare() (see Executing statements)


• Bind all variables by calling one of the OCI_Bindxxxxx() function for every input variable
referenced by the SQL statement
• Setup up values of the program variables
• Call OCI_Execute() as many times as needed
• Each OCI_Execute() call may be preceded by an update of the program variables (for INSERTs for
example)

OCILIB does not pre-parse statements (like other frameworks such as JDBC ...) and lets Oracle recognize
input variables embedded within the SQL statements. Bind variables must be preceded in the SQL code by
the character ':'.

Oracle and OCILIB supports two ways of binding:

• by name (default mode in OCILIB): Oracle looks for variables in the SQL statement by searching
their names provided to the binding function. So a variable can be binded once and used many
times in the statement
• by position: Oracle binds variables by position, so every variable is binded with a position number

OCILIB Default binding mode is OCI_BIND_BY_NAME.

When using binding by position, provide the position to OCI_BindXXXX() call through the name
parameter. Within this mode the bind name must be the position preceded by a semicolon like ':1', ':2',

Note: Rebinding is disabled by default (see OCI_AllowRebinding())

In the previous example, the query was simple and did not require any input variable. Often, it is
necessary to request handle values that are not known at compilation time. Moreover, it is useful to run
several times the same SQL statement with different values without having to re-prepare the same SQL
Oracle to optimize performance.

OCI_Connection *cn;
OCI_Statement *st;
int code;
/* ... */

st = OCI_StatementCreate(cn);
OCI_Prepare(st, "delete from test_fetch where code = :code");
OCI_BindInt(st, ":code", &code);
code = 3;
OCI_Execute(st);
printf("%d row deleted"; OCI_GetAffectedRows(st));

code = 56;
OCI_Execute(st);
printf("%d row deleted"; OCI_GetAffectedRows(st));
OCI_Commit(cn);

To make a mass insertion, we can proceed as follows:

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 19

OCI_Connection *cn;
OCI_Statement *st;
int code;
char name[30];
char value[20];
/* ... */
st = OCI_StatementCreate(cn);

OCI_Prepare(st, "insert into my_table values(:code, :name, :value)");


OCI_BindInt(st, ":code", &code);
OCI_BindString(st, ":name", name, 30);
OCI_BindString(st, ":value", value, 20);
for (code = 1; code < 1000; code++);
{
sprintf(name, "name %i", code);
sprintf(value, "value %i", code);
OCI_Execute(st);
}
OCI_Commit(cn);

/* ... */

However, Oracle supports "bulks operations" (see Chapter 6) that allows host arrays binding and thus a
major increase of performance.

Retrieving the result of a query

OCILIB offers a really easy and smart mechanism to fetch data from a SQL Statement. It looks like what's
found in JDBC and other object oriented databases frameworks.

Only SELECT statements, DML with returning clause and some PL/SQL blocks return a cursor that can be
fetched by host programs. That cursor, or resultset, is encapsulated in OCILIB by the OCI_Resultset
object.

So, after any successful call to an OCI_Executexxx() function that executed a fetchable statement or filled
output bind variables, the resultset can be retrieved by calling OCI_GetResultset()

The creation of a OCI_Resultset object consists in :

• Describing the output columns of the resultset


• Allocating memory to hold the content data

OCILIB supports multi-row fetching for increasing performances. Instead of fetching data row by row from
the server (that induces lots of roundtrips between the client and the server), the library prefetches data
chunk by chunks (default is 20 rows). So, less network traffic and better performances.
These mechanisms are completely hidden from the application which fetches the resultset row by row.

Once the Resultset handle is retrieved:

• It can be fetched by calling OCI_FetchNext() as long as it returns TRUE.


• To retrieve the value of a column, call OCI_GetXXXX() where XXXX is the type of data you want to
fetch.

Note: If the column internal data does not match the requested type, OCILIB tries to convert the data
when it's possible and throws an error if not.

The properties (columns names, types ...) of the resultset are accessible through a set of APIs.

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 20

#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Resultset *rs;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);
st = OCI_StatementCreate(cn);
OCI_ExecuteStmt(st, "select * from products");
rs = OCI_GetResultset(st);
while (OCI_FetchNext(rs))
printf("code: %i, name %s\n", OCI_GetInt(rs, 1) , OCI_GetString(rs, 2));
printf("\n%d row(s) fetched\n", OCI_GetRowCount(rs));
OCI_Cleanup();
return EXIT_SUCCESS;
}

In this example, OCI_GetRowCount() returns the number of rows fetched so far.

Note: you can access the resultset columns values by column name instead of position by calling
OCI_GetXXX2() functions.

A statement object can be reused as many times as desired. Moreover, it is possible to create multiple
statements and fetch them simultaneously, even nested.

OCI_Connection *cn;
OCI_Statement *st1, *st2;
OCI_Resultset *rs;
/* ... */
st1 = OCI_StatementCreate(cn);
st2 = OCI_StatementCreate(cn);

int code;
OCI_ExecuteStmt(st1, "select code from my_table");
OCI_Prepare(st2, "delete from my_table2 where code_ref = :code");
OCI_Bind(st2, ":code", &code);

rs = OCI_GetResultset(st);
while (OCI_FetchNext(rs))
{
code = OCI_GetInt(rs, 1);

OCI_Execute(st2);
}

Resultset metadata information

It is possible to retrieve metadata information about each column of resultset. To do this:

• OCI_GetColumnCount() returns the number of columns in the resultset


• OCI_GetColumn() returns the column object at the given position in the resultset
• OCI_GetColumn2() returns the column object from its name in the resultset
• All properties of the returned column object are accessible by a series of functions
OCI_GetColumnXXX() where XXX is the property

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 21

#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Resultset *rs;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("db", "usr", pwd", OCI_SESSION_DEFAULT);
st = OCI_StatementCreate(cn);
OCI_ExecuteStmt(st, "select * from my_table");
rs = OCI_GetResultset(st);
nb = OCI_GetColumnCount(rs);
for(i = 1; i <= nb; i++)
{
col = OCI_GetColumn(rs, i);
printf("%-20s%-10s%-8i%-8i%-8i%-s\n",
OCI_GetColumnName(col),
OCI_GetColumnSQLType(col),
OCI_GetColumnSize(col),
OCI_GetColumnPrecision(col),
OCI_GetColumnScale(col),
OCI_GetColumnNullable(col) == TRUE ? "Y" : "N");
}
OCI_Cleanup();
return EXIT_SUCCESS;
}

Implicit conversions

OCI_GetString() performs an implicit conversion from the following datatypes:

• Numerics (based on the current connection handle numeric format)


• OCI_Date (based on the current connection handle date format)
• OCI_Timestamp (based on the current connection handle date format)
• OCI_Interval (based on Oracle default conversion)
• OCI_Lob (maximum number of character is defined by OCI_SIZE_BUFFER)
• OCI_Long
• OCI_File (maximum number of character is defined by OCI_SIZE_BUFFER)
• RAW buffer

The following types are not supported for implicit conversion:

• OCI_Statement
• OCI_Coll
• OCI_Object

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 22

Scrollable statements

OCILIB supports scrollable cursors introduced with Oracle 9i. These cursors (resultsets in OCILIB terms)
can be fetched:

• Sequentially in both directions : OCI_FetchPrev() and OCI_FetchPrev()


• To a relative position in the resultset : OCI_FetchSeek() with OCI_SFD_RELATIVE
• To an absolute position in the resultset : OCI_FetchSeek() with OCI_SFD_ABOSLUTE
• To the first or last row in the resultset : OCI_FetchFirst() and OCI_FetchLast()

Scrollable statements use more server and client resources and should only be used when necessary.

Resultsets are 'forward only' by default. Call OCI_SetFetchMode() with OCI_SFM_SCROLLABLE to enable
scrollable resultsets for a given statement.

Warning: Any use of scrollable fetching functions with a resultset that depends on a statement with fetch
mode set to OCI_SFM_DEFAULT will fail!

#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Resultset *rs;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);
st = OCI_StatementCreate(cn);
OCI_SetFetchMode(st, OCI_SFM_SCROLLABLE);
OCI_ExecuteStmt(st, "select int_col1, str_col from my_table");
rs = OCI_GetResultset(st);
/* get resultset row count */
OCI_FetchLast(rs);
printf("resultset contains %i rows\n", OCI_GetRowCount(rs));
/* go to row 1 */
OCI_FetchFirst(rs);
printf("%i - %s\n", OCI_GetInt(rs, 1), OCI_GetString(rs, 2));
/* enumerate from row 2 to row X */
while (OCI_FetchNext(rs))
printf("%i - %s\n", OCI_GetInt(rs, 1), OCI_GetString(rs, 2));
/* enumerate from row X back to row 1 */
while (OCI_FetchPrev(rs))
printf("%i - %s\n", OCI_GetInt(rs, 1), OCI_GetString(rs, 2));
/* print the 30th row */
OCI_FetchSeek(rs, OCI_SFD_ABSOLUTE, 30);
printf("%i - %s\n", OCI_GetCurrentRow(rs), OCI_GetInt(rs, 1), OCI_GetString(rs, 2));
/* fetch next 30 rows */
while ((OCI_GetCurrentRow(rs) < 60) << OCI_FetchNext(rs))
printf("%0i - %s\n", OCI_GetInt(rs, 1), OCI_GetString(rs, 2));
/* move back to the 45th row */
OCI_FetchSeek(rs, OCI_SFD_RELATIVE, -15);
printf("%i - %s\n", OCI_GetInt(rs, 1), OCI_GetString(rs, 2));
OCI_Cleanup();
return EXIT_SUCCESS;
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 23

PL/SQL blocks

OCILIB has a strong PL/SQL support:

• Blocks, procedures and function can be used with OCILIB statements.


• Ref cursors
• Nested tables
• Tables (indexed by integer types)
• Access to the server side output generated by the DBMS_OUTPUT package

Stored procedures/functions calls, blocks declarations are done like regular SQL calls using
OCI_Prepare(), OCI_Execute(), OCI_ExecuteStmt() and OCI_ExecuteStmtFmt() functions.

All PL/SQL statements must:

• start with a 'begin' or 'declare' keyword


• end with a 'end;' keyword

/* basic PL/SQL call */

OCI_Statement *st;
st = OCI_StatementCreate(cn);
OCI_Prepare(st, "begin :n := trunc(sysdate+1)-trunc(sysdate-1); end;");
OCI_BindInt(st, ":n", &n);
OCI_Execute(st);
printf("Result : %i\n", n);

/* Retrieving a PL/SQL cursor and fetch its results inside a C program : */


#include "ocilib.h"

int main()
{
OCI_Connection *cn;
OCI_Statement *st1; *st2;
OCI_Resultset *rs;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("db", "usr", pwd", OCI_SESSION_DEFAULT);
st1 = OCI_StatementCreate(cn);
st2 = OCI_StatementCreate(cn);
OCI_Prepare(st1, "begin open :c for select * from my_table; end;");
OCI_BindStatement(st2, ":c", st2);
OCI_Execute(st1);
rs = OCI_GetResultset(st2);
while (OCI_FetchNext(rs))
{
printf("value %s\n", OCI_GetString(rs, 1));
}
OCI_Cleanup();
return EXIT_SUCCESS;
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 24

/* Retrieving server output */


#include "ocilib.h"

int main(void)
{
OCI_Connection *cn;
OCI_Statement *st;
const dtext *p;

if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))


return EXIT_FAILURE;

cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);


st = OCI_StatementCreate(cn);

OCI_ServerEnableOutput(cn, 32000, 5, 255);


OCI_ExecuteStmt(st, "begin "
" dbms_output.put_line('First line'); "
" dbms_output.put_line('Second line'); "
"end;"
);
while (p = OCI_ServerGetOutput(cn))
{
printf(%s\n", p);
}
OCI_Cleanup();

return EXIT_SUCCESS;
}

Support for SQL RETURNING clause

OCILIB supports the Oracle feature 'Returning into' for DML statements.

Let's Oracle talk about this feature:

'Using the RETURNING clause with a DML statement allows you to essentially combine two SQL
statements into one, possibly saving you a server round-trip. This is accomplished by adding an extra
clause to the traditional UPDATE, INSERT, and DELETE statements. The extra clause effectively adds a
query to the DML statement. In the OCI, the values are returned to the application through the use of
OUT bind variables.'

OCILIB implements this features by providing a set of functions that allows registering output
placeholders for the returned values. Once the DML is executed with OCI_Execute(), the output returned
data is available through a regular resultset object that can be fetched.

Array binding interface is also supported with 'returning into' DML statement. Every iteration (or row of
given arrays) generates a resultset object. Once a resultset is fetched, the next on can be retrieved with
OCI_GetNextResultset().

OCI_Long are not supported for 'returning into' clause .This is a limitation imposed by Oracle.

OCI_Column objects retrieved from output OCI_Resultset have the following particularities:

• Their names are the provided bind names to the DML statement (by example, ‘out1’). So any call
to the functions OCI_GetXXX2() should be aware of it
• The detailed SQL columns attributes might be not all set or accurate. By example, the scale and
precision are not set, the SQL type is the one chosen by OCILIB regarding the OCILIB object
datatype and might be slightly different from the real one...

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 25

#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Resultset *rs;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);
st = OCI_CreateStatement(cn);
OCI_Prepare(st, "update products set code = code+10 returning code into :i");
OCI_RegisterInt(st, ":i");
OCI_Execute(st);
rs = OCI_GetResultset(st);
while (OCI_FetchNext(rs))
printf("%i\n", OCI_GetInt(rs, 1));
printf("count : %i\n", OCI_GetRowCount(rs));
OCI_Commit(cn);

OCI_Cleanup();
return EXIT_SUCCESS;
}

Statements extra control

OCILIB offers a range of features to customize the behavior of a statement.

For example, you can specify:

• The number of rows pre-fetchées by the Oracle client to reduce the number of roundtrips to the
server
• The number of lines fetched internally by OCILIB to reduce calls OIC
• The way of linking variables: by position or by name
• The date format by default
• Etc. ..

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 26

6. Bulk Operations
The "bulk operations" are a powerful feature supported by Oracle that can perform mass updates (insert /
update / update) of tables in record time.

In a classic pattern, if one wishes to insert 1000 rows into a table for example, you can:

• prepare the application


• bind variables
• loop from 1 to 1000 to run the SQL bearing in each loop updated values.

This scheme will generate 1000 calls for execution of the request and then 1000 return trips to the
server:

• Transmitting values
• Rerun the SQL

All these calls and return trips are expensive for the network in terms of performance! If you want to
insert 1 million rows, it can be long!

Oracle proposes a simple solution that achieves optimal performance: OCI Array Interface.

Oracle Array interface

OCILIB supports the OCI array Interface by binding arrays of C scalar types and OCILIB object types.

• all types supported by the library can be used for array binding except OCI_Statement and
OCI_Long
• Array binding is really fast for massive DML operations
• For string/RAW arrays, the input array MUST BE a contiguous block of data and not an array of
pointers. So to bind an array of 10 elements for a varchar2(30) column, binded variable must be a
like array[10][31]

In the preceding example, network traffic generated by a large number of single query executions is the
main source of the slow final treatment.

Oracle intends to minimize this traffic by providing arrays.


Instead of providing 1 variable and send to 1000 times its value to the server, it provides an array of
1000 values that are sent at once.

This system reduces the processing time by factors of 3 to 5 digits or more on large volumes.

OCILIB supports this mechanism and provides the ability to bind arrays of any type supported by OCILIB
(except OCI_Long and OCI_Statement)

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 27

Example

#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
int tab_int[1000];
char tab_str[1000][21];
int i;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
/* ... create connection and statement ... */
cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);
st = OCI_StatementCreate(cn);
/* binding */
OCI_Prepare(st, "insert into products values(:i, :s)");
OCI_BindArraySetSize(st, 1000);
OCI_BindArrayOfInts(st, ":i", (int*) tab_int, 0);
OCI_BindArrayOfStrings(st, ":s", (char*) tab_str, 20, 0);

/* filling arrays */
for(i = 0; i < 1000 ; i++)
{
tab_int[i] = i+1;
sprintf(tab_str[i],"Name %d",i+1);
}
/* execute */
OCI_Execute(st);

printf("row processed : %d\n", OCI_GetAffectedRows(st));


OCI_Commit(cn);
OCI_Cleanup();

return EXIT_SUCCESS;
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 28

7. Using Larges Objects


Oracle 8 introduced the LOBs (Large Objects) in order to store and manipulate large objects of size (>
several GB) to meet the storage needs of large files (multimedia, video, ...) and raw data within the DB.

There are basically 2 types of large objects:

• The BLOB / CLOB: objects stored in binary (BLOB) / text (CLOB)


• The BFILE: objects not stored in the DB. These are pointers to files accessible by the server (on the
same file system or not) and are manipulated by the client application

OCILIB fully supports these data types.

Moreover, OCILIB also supports the old implementation of LOBs: types LONG, RAW and LONG RAW.
These types always maintained by Oracle, are the "ancestors" of LOBs and accounted for in earlier
versions (up to Oracle 7) the only way to store large volumes (but limited) in the DB.

Types LONG are still being widely used in the Oracle databases and applications.

Therefore OCILIB provides an API very similar to those of LOBs (while the undercoat OIC LONGWORDs
management is very different from LOBs).

Internal Objects (LOBs)

OCILIB encapsulates Lobs by supplying:

• An OCI_Lob C type
• A set of really easy APIs to manipulate OCI_Lob objects

OCILIB currently supports 3 types of Lobs :

• BLOB : Binary LOBs (replacement for LONG RAW datatype)


• CLOB : Character LOBs (replacement for LONG datatype)
• NCLOB : National Character LOBs

OCI_Lob objects can be:

• Created as standalone instances


• Used for in/out binding
• Retrieved from select statements
• Manipulated (copy, append, ...)

Oracle 10g extended lobs by increasing maximum size from 4Go to 128 To.

OCILIB, with version 2.1.0, supports now this new limit. For handling sizes and offsets up to 128 To, 64
bit integers are requested.

So, a new scalar integer type has been introduced: big_uint (elderly lobsize_t). This type can be a 32 bits
or 64 bits integer depending on:

• Compiler support for 64 bits integers (C99 compiler, MS compilers)


• Oracle client version

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 29

big_uint will be a 64 bits integer :

• if the compiler supports it


• if OCILIB is build with option OCI_IMPORT_LINKAGE and the Oracle version is >= 10.1
• or OCILIB is build with option OCI_IMPORT_RUNTIME (oracle version is not known at compilation
stage)

#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Lob *lob1, *lob2;
int code, n;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);
st = OCI_StatementCreate(cn);
OCI_ExecuteStmt(st, "select code, content from test_lob for update");
rs = OCI_GetResultset(st);
while (OCI_FetchNext(rs))
{
code = OCI_GetInt(rs, 1);
lob1 = OCI_GetLob(rs, 2);
lob2 = OCI_LobCreate(cn, OCI_CLOB);
n = OCI_LobWrite(lob1, "Today, ", 7);
OCI_LobSeek(lob1, n, OCI_SEEK_SET);
n = OCI_LobWrite(lob2, "I'm going to the cinema !", 25);
OCI_LobAppendLob(lob1, lob2);
OCI_LobSeek(lob1, 0, OCI_SEEK_SET);
n = OCI_LobRead(lob1, temp, 100);
temp[n] = 0;
printf("code: %i, action : %s\n", code, temp);

OCI_LobFree(lob2);
}

printf("\n%d row(s) fetched\n", OCI_GetRowCount(rs));


OCI_Cleanup();
return EXIT_SUCCESS;
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 30

Example to insert the contents of a file in a BLOB field in a table:

#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Lob *lob;
FILE *f;
unsigned char buffer[1024];
int size;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);
st = OCI_StatementCreate(cn);
f = fopen("My file", "rb");

if (f != NULL)
{
fseek (f , 0 , SEEK_END);
size = ftell(f);
rewind (f);

printf("\nTotal bytes to write : %d\n", size);


lob = OCI_LobCreate(cn, OCI_BLOB);
OCI_Prepare(st, "insert into my_blob_table(code, content) values (1, :data)");
OCI_BindLob(st, ":data", lob);
OCI_Execute(st);
/* write data into table by chunks of 1024 bytes */
while ((n = fread(buffer, 1, sizeof(buffer), f)))
{
OCI_LobWrite(lg, buffer, n);
}
printf("\nTotal bytes written : %s\n", OCI_LobGetLenght(lob));
fclose(f);
OCI_Commit(cn);
OCI_LobFree(lob);
}
OCI_Cleanup();

return EXIT_SUCCESS;
}

External Objects (FILEs)

Objects of type FILE (OCI_File) are references to external files in the DB which can be opened for read by
the server and the content can be retrieved by the client application.

The object files are similar to LOBs and therefore their API is similar except that the files are read-only.

OCILIB encapsulates FILEs by supplying:

• An OCI_File C type
• A set of really easy APIs to manipulate OCI_File objects

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 31

OCILIB currently supports 2 types of FILEs:

• BFILE : Binary files


• CFILE : Character files

Warning: FILEs are read-only.

#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_File *file;
char buffer[256];
int n;

if (!OCI_Initialize(err_handler, NULL, OCI_ENV_DEFAULT))


return EXIT_FAILURE;

cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);


st = OCI_StatementCreate(cn);

file = OCI_FileCreate(cn, OCI_CFILE);


OCI_FileSetName(file, "MYDIR", "MyfileName");
/* check if faile exists */

if (OCI_FileExists(file))
{
printf("file size : %d\n", OCI_FileGetSize(file));
printf("file dir : %s\n", OCI_FileGetDirectory(file));
printf("file name : %s\n", OCI_FileGetName(file));
}
/* bind for inserting into table */
OCI_Prepare(st, "insert into my_bfile_table(code, value) values (1, :bfile)");
OCI_BindFile(st, ":bfile", file);
OCI_Execute(st);
OCI_Commit(cn);
/* free local file object */
OCI_FileFree(file),

/* fetch bfile data from table */


OCI_ExecuteStmt(st, "select code, value from my_bfile_table");
rs = OCI_GetResultset(st);

while (OCI_FetchNext(rs))
{
file = OCI_GetFile(rs, 2);
OCI_FileOpen(file);
printf("file size %d\n", OCI_FileGetSize(file));
printf("file dir %s\n", OCI_FileGetDirectory(file));
printf("file name %s\n", OCI_FileGetName(file));
while (n = OCI_FileRead(file, buffer, sizeof(buffer)-1))
{
buffer[n] = 0;
printf(buffer);
}
OCI_FileClose(file);
}
OCI_Cleanup();
return EXIT_SUCCESS;
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 32

Long Objects

OCILIB implements the "old" Long (OCI_Long *) similarly to LOBs and files.

The APIs for handling LONGWORDs fields are very close to those of Large Objects.

Long Objects encapsulate Oracle LONGs datatypes and were used to store large buffers in Oracle
database.

They're still supported but are depreciated. Oracle now provides a newer and better way to deal with data
that needs large storage: LOBs

OCILIB supports this datatype because it was and still is widely used

OCILIB provides a set of API for manipulating LONGs that is really close to the one provided for LOBs.

OCILIB currently supports 3 types of Long Objects:

• OCI_BLONG : LONG RAW columns


• OCI_CLONG : LONG columns

OCI_Long objects can be:

• Created as standalone instances


• Used for in/out binding
• Retrieved from select statement

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 33

#include "ocilib.h"

#define FILENAME "data.lst"


int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Long *lg;
FILE *f;
char buffer[2048];
int n;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);
st = OCI_StatementCreate(cn);
/* INSERT LONGS -------------------------------------------- */

f = fopen(FILENAME, "rb");
if (f)
{
fseek (f , 0 , SEEK_END);
n = ftell(f);
rewind (f);
printf("\n%d bytes to write\n", n);

lg = OCI_LongCreate(st, OCI_BLONG);
OCI_Prepare(st, "insert into test_long_raw(code, content) values (1, :data)");
OCI_BindLong(st, ":data", lg, n);
OCI_Execute(st);

/* write data into table by chunks of 2048 bytes */


while ((n = fread(buffer, 1, sizeof(buffer), f)))
{
OCI_LongWrite(lg, buffer, n);
}

printf("\n%d bytes written\n", OCI_LongGetSize(lg));


fclose(f);

OCI_LongFree(lg);
OCI_Commit(cn);
}
/* FETCHING LONGS -------------------------------------------- */

OCI_ExecuteStmt(st, "select content from test_long_raw where code = 1");


OCI_SetLongMaxSize(st, 1000000);
rs = OCI_GetResultset(st);

/* read data by chunks of 2048 bytes*/


while (OCI_FetchNext(rs))
{
lg = OCI_GetLong(rs, 1);
while ((n = OCI_LongRead(lg, buffer, sizeof(buffer)))) {}
printf("\n%d bytes read\n", OCI_LongGetSize(lg));
}
OCI_Cleanup();
return EXIT_SUCCESS;
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 34

8. Using dates and timestamps

Date handles

OCILIB can manipulate Oracle dates (day / hour) with ease.

Example where a date is retrieved from a table and displayed, incremented by 5 days and 2 months and
then redisplayed:

#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Date *dt;
char str[100];
int n;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);
st = OCI_StatementCreate(cn);
OCI_ExecuteStmt(st, "select mon_champs_date from my_table");
rs = OCI_GetResultset(st);
while (OCI_FetchNext(rs))
{
dt = OCI_GetDate(rs, 1);

OCI_DateToText(dt, "DD/MM/YYYY HH24:MI:SS", sizeof(str)-1, str);


printf("Date is %s\n", str);
OCI_DateAddDays(dt, 5);
OCI_DateAddMonths(dt, 2);
OCI_DateToText(dt, "DD/MM/YYYY HH24:MI:SS", sizeof(str)-1, str);
printf("Date + 5 days and 2 months is %s\n", str);
}
OCI_Cleanup();

return EXIT_SUCCESS;
}

Timestamp handles

The timestamps are extensions to the type DATE:

• manage precise dates through the management of fractions of seconds


• manage time zones

Example where the date / time is retrieved from the server and displayed with fractional seconds:

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 35

#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Timestamp *tm;
char str[100];
int n;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);
st = OCI_StatementCreate(cn);
OCI_ExecuteStmt(st, "SELECT CURRENT_TIMESTAMP FROM dual");
rs = OCI_GetResultset(st);
OCI_FetchNext(rs);
tm = OCI_GetTimestamp(rs, 1);
OCI_TimestampToText(tm, "DD/MM/YYYY HH24:MI:SS:FF3\n", 100, str, 3);
printf(str);
OCI_Cleanup();

return EXIT_SUCCESS;
}

Interval handles

The intervals are periods of time expressed:

• in years and months


• in days, hours, minutes and seconds

They can perform operations on timestamps. Example where the date / time is retrieved from local
variable tm, then incremented by 1 day, 1 hour, 1 minute and 1 seconds and then displayed with
fractional seconds:

#include "ocilib.h"
#define SIZE_STR 260
int main()
{
OCI_Timestamp *tm;
OCI_Interval *itv;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
tm = OCI_TimestampCreate(NULL, OCI_TIMESTAMP);
itv = OCI_IntervalCreate(NULL, OCI_INTERVAL_DS);
OCI_TimestampSysTimeStamp(tm);
OCI_TimestampToText(tm, "DD/MM/YYYY HH24:MI:SS:FF3", SIZE_STR, str, 3);
printf("%s\n", str);
OCI_IntervalSetDaySecond(itv, 1,1,1,1,0);
OCI_IntervalToText(itv, 10, 10, SIZE_STR, str);
printf("%s\n", str);
OCI_TimestampIntervalAdd(tm, itv);
OCI_TimestampToText(tm, "DD/MM/YYYY HH24:MI:SS:FF3", SIZE_STR, str, 3);
printf("%s\n", str);
OCI_TimestampFree(tm);
OCI_IntervalFree(itv);
OCI_Cleanup();
return EXIT_SUCCESS;
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 36

9. Using Oracle objects (U.D.T. / Named Types)


OCILIB supports the "Named types", i.e. data types named by the user created or supplied by Oracle.

A "TYPE" Oracle is seen as equivalent to a C structure. This is an aggregation of fields of scalar or


aggregated types.

create type t_produit as object


(
code number,
libelle varchar2(30),
prix number(5,3),
reference varchar2(100)
);
create table ventes_produits
(
product t_produit,
nombre int,
date_vente date
);

OCILIB implements Oracle Named types (user types and built-in types) through the OCI_Object type.

OTT and C structures are not required to use objects in OCILIB.

In order to manipulate objects attributes, OCILIB proposes a set of functions to get/set properties for
various supported types.

Objects can be:

• Created as standalone instances (transient objects)


• Used for binding (persistent / transient objects)
• Retrieved from select statements (persistent / embedded objects)

References (Oracle type REF) are identifiers (smart pointers) to objects and are implemented in OCILIB
with the type OCI_Ref.

OCILIB implements Oracle REFs as strong typed Reference (underlying OCI REFs are weaker in terms of
typing). It means it's mandatory to provide type information to:

• create a local OCI_Ref handle.


• register an OCI_Ref handle for a 'returning into' clause.

Note: See Oracle Database SQL Language Reference for more details about REF datatype

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 37

Autonomous Instances

To create an autonomous instance, you first, must get a descriptor.

This is achieved by a call to OCI_TypeInfoGet().

#include "ocilib.h"

int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Resultset *rs;
OCI_Object *prod;
OCI_Date *date;
int qte;

if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))


return EXIT_FAILURE;

cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);


st = OCI_StatementCreate(cn);
prod = OCI_ObjectCreate(cn, OCI_TypeInfoGet(cn, "t_product", OCI_TIF_TYPE);
date = OCI_DateCreate(cn);

qte = 356;
OCI_DateSysDate(date);

OCI_ObjectSetInt(prod, "CODE", 1);


OCI_ObjectSetString(prod, "LIBELLE", "USB KEY 2go");
OCI_ObjectSetDouble(prod, "PRIX", 12.99);
OCI_ObjectSetString(prod, "REFERENCE", "A56547WSAA");

OCI_Prepare(st, "insert into ventes_produits values(:p, :n, :d)");

OCI_BindObject(st, ":p", prod);


OCI_BindInt(st, ":n", &qte);
OCI_BindDate(st, ":d", date);
OCI_Execute(st);

printf("\n%d row(s) inserted\n", OCI_GetAffectedRows(st));

OCI_Commit(cn);
OCI_ObjectFree(obj);
OCI_Cleanup();

return EXIT_SUCCESS;
}

Selecting objects

Objects can be selected in the same way as the SQL data types.

#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Resultset *rs;
OCI_Object *prod;
OCI_Date *date;
int qte;

if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))


return EXIT_FAILURE;

cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);


st = OCI_StatementCreate(cn);

OCI_ExecuteStmt(st, "select * from ventes_produits");

rs = OCI_GetResultset(st);
while (OCI_FetchNext(rs))
{
prod = OCI_GetObject(rs, 1);
qte = OCI_GeInt(rs, 2);
date = OCI_GetDate(rs, 3);

printf("Produit : %s, Ventes : %i\n", OCI_ObjectGetString(prod, "LIBELLE"), qte);


}

OCI_Cleanup();
return EXIT_SUCCESS;
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 38

10. Using Oracle Collections

Collections types

OCILIB supports all Oracle collections:

• PL/SQL Tables: only available in PL/SQL, unbounded, sparse arrays of homogeneous elements.
• Varrays: available in SQL and PL/SQL, they are bounded arrays of homogeneous elements
• Nested Tables: available in SQL and PL/SQL, they are unbounded arrays of homogeneous elements
and can become sparse through deletions

PL/SQL tables are implemented by binding regular C arrays with the array interface (using
OCI_BindArrayOfXXX() calls)

Varrays and Nested tables are implemented in OCILIB with the type OCI_Coll. It's possible to bind and
fetch Varrays and Nested tables using OCI_Coll handle.

It's also possible to declare local collections based on some database type without using queries

OCI (and thus OCILIB) offers the possibility to access collection elements:

• directly by index (OCI_CollGetAt() and OCI_CollSetAt())


• using an iterator (OCI_Iter) to iterate through the collection (OCI_IterGetNext(),
OCI_IterGetPrev())

Collection Items are implemented through the type OCI_Elem and use the series of calls
OCI_ElemGetXXX() and OCI_ElemSetXXX() to manipulate elements content values

Example

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 39

#include "ocilib.h"
int main(void)
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Resultset *rs;
OCI_Coll *coll;
OCI_Iter *iter;
OCI_Elem *elem;
OCI_TypeInfo *type;
OCI_Object *obj;
int i, n;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;

cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);

/* Varray binding -------------------------------------------------------- */


st = OCI_StatementCreate(cn);

/* create the collection */


type = OCI_TypeInfoGet(cn, "Varray_type", OCI_TIF_TYPE);
coll = OCI_CollCreate(type);

/* bind the local collection to a PL/SQL procedure */


OCI_Prepare(st, "begin load_array(:array); end;");
OCI_BindColl(st, ":array", coll);
OCI_Execute(st);
/* the procedure has filled the collection and
we can iterate it using an iterator */
iter = OCI_IterCreate(coll);
elem = OCI_IterGetNext(iter);

while (elem != NULL)


{
printf("value %s\n", OCI_ElemGetString(elem));
elem = OCI_IterGetNext(iter);
}

OCI_IterFree(iter);
OCI_CollFree(coll);

/* Varray SQL fetch ------------------------------------------------------- */

/* query on a table with varray column */

OCI_ExecuteStmt(st, "SELECT * from table_article");

rs = OCI_GetResultset(st);

while (OCI_FetchNext(rs))
{
/* iterate the collection using an iterator */

coll = OCI_GetColl(rs, 2);

iter = OCI_IterCreate(coll);
elem = OCI_IterGetNext(iter);

printf("article #%d\n", OCI_GetInt(rs, 1));

while (elem != NULL)


{
obj = OCI_ElemGetObject(elem);
printf(".... code %d, name%s \n", OCI_ObjectGetInt(obj, "ID"),
OCI_ObjectGetString(obj, "NAME"));
elem = OCI_IterGetNext(iter);
}
OCI_IterFree(iter);
}
/* Nested table fetch ------------------------------------------------------- */
/* query on a table with nested table column */

OCI_ExecuteStmt(st, "SELECT * from table_sales");

rs = OCI_GetResultset(st);
while (OCI_FetchNext(rs))
{
coll = OCI_GetColl(rs, 2);

printf("Sale #%d\n", OCI_GetInt(rs, 1));

/* iterate the collection by accessing element by index */


n = OCI_CollGetSize(coll);
for(i = 1; i <= n; i++)
{
elem = OCI_CollGetAt(coll, i);
obj = OCI_ElemGetObject(elem);
printf(".... employee %s, amount %s \n", OCI_ObjectGetString(obj, "EMP"),
OCI_ObjectGetString(obj, "AMOUNT"));
}
}
OCI_Cleanup();

return EXIT_SUCCESS;
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 40

11. Loading data with Direct Path mode

Oracle Direct Path Loading

Oracle provides an API to load data directly into the tables without using the SQL engine.

OCILIB (from version 3.2.0) support the OCI direct Path API.

Actual implementation of direct path API does not support the following elements:

• Objects datatypes (User Defined Types and Object References)


• Object tables
• Nested tables
• SQL String functions

All scalar datatypes (numerics, characters and date/time), including LOBs and LONG types are supported

Oracle direct API features (from Oracle Documentation) :

“The direct path load interface allows an application to access the direct path load engine of the Oracle
database server to perform the functions of the Oracle SQL*Loader utility. This functionality provides the
ability to load data from external files into Oracle database objects, either a table or a partition of a
partitioned table. The OCI direct path load interface has the ability to load multiple rows by loading a
direct path stream which contains data for multiple rows.”

Oracle direct API limitation (from Oracle Documentation)

“The direct path load interface has the following limitations which are the same as SQL*Loader:

• triggers are not supported


• check constraints are not supported
• referential integrity constraints are not supported
• clustered tables are not supported
• loading of remote objects is not supported
• user-defined types are not supported
• LOBs must be specified after all scalar columns
• LONGs must be specified last”

Warning: It is recommended to use direct path interface with an Oracle client that is the same version
than the database. With version < 10g, it is mandatory regarding that it causes segmentation faults and
it's known from Oracle that advices to use the same version for client and server (see metalink KB)

How to use direct path:

1. Create a direct path handle with OCI_DirPathCreate()


2. Set (optional) some direct path load attributes
3. Describe the columns to load with OCI_DirPathSetColumn()
4. Populate data with OCI_DirPathSetEntry()
5. Convert the data with OCI_DirPathConvert()
6. Load the data into the database with OCI_DirPathLoad()
7. Repeat step 4,5,6 + reset the stream with OCI_DirPathReset() until all rows has been loaded
8. Commit the load with OCI_DirPathFinish()
9. Free the direct path handle with OCI_DirPathFree()

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 41

Example

#include "ocilib.h"

#define SIZE_ARRAY 1000


#define SIZE_COL1 20
#define SIZE_COL2 30
#define SIZE_COL3 8
#define NUM_COLS 3

int main(void)
{
OCI_Connection *cn;
OCI_DirPath *dp;
OCI_TypeInfo *tbl;

dtext val1[SIZE_COL1+1];
dtext val2[SIZE_COL2+1];
dtext val3[SIZE_COL3+1];

int i = 0, nb_rows = SIZE_ARRAY;

if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))


return EXIT_FAILURE;

cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);


tbl = OCI_TypeInfoGet(cn, "test_directpath", OCI_TIF_TABLE);
dp = OCI_DirPathCreate(tbl, NULL, NUM_COLS, nb_rows);

/* optional attributes to set */

OCI_DirPathSetBufferSize(dp, 64000);
OCI_DirPathSetNoLog(dp, TRUE);
OCI_DirPathSetParallel(dp, TRUE);

/* describe the target table */

OCI_DirPathSetColumn(dp, 1, "VAL_INT", SIZE_COL1, NULL);


OCI_DirPathSetColumn(dp, 2, "VAL_STR", SIZE_COL2, NULL);
OCI_DirPathSetColumn(dp, 3, "VAL_DATE", SIZE_COL3, "YYYYMMDD");

/* prepare the load */

OCI_DirPathPrepare(dp);
nb_rows = OCI_DirPathGetMaxRows(dp);

for (i = 1; i <= nb_rows; i++)


{
/* fill test values */

sprint_dt(val1, SIZE_COL1+1, "%04d", i);


sprint_dt(val2, SIZE_COL2+1, "value %05d", i);
sprint_dt(val3, SIZE_COL3+1, "%04d%02d%02d", (i%23)+1 + 2000,
(i%11)+1,
(i%23)+1);

OCI_DirPathSetEntry(dp, i, 1, val1, (unsigned int) strlen(val1), TRUE);


OCI_DirPathSetEntry(dp, i, 2, val2, (unsigned int) strlen(val2), TRUE);
OCI_DirPathSetEntry(dp, i, 3, val3, (unsigned int) strlen(val3), TRUE);
}

/* load data to the server */

OCI_DirPathConvert(dp);
OCI_DirPathLoad(dp);

/* commits changes */
OCI_DirPathFinish(dp);

printf("%04d row(s) processed\n", OCI_DirPathGetAffectedRows(dp));


printf("%04d row(s) loaded\n", OCI_DirPathGetRowCount(dp));

/* free direct path object */

OCI_DirPathFree(dp);

OCI_Cleanup();

return EXIT_SUCCESS;
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 42

12. Advanced features

Describing tables in a schema

#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_TypeInfo *tbl;
int n;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);
tbl = OCI_TypeInfoGet(cn, "MyTable", OCI_TIF_TABLE);
if (tbl)
{
printf ("Column Name Type Length Prec. Scale Null ?\n");
printf ("---------------------------- ------------------------------\n");
n = OCI_TypeInfoGetColumnCount(tbl);
for(i = 1; i <= n; i++)
{
col = OCI_TypeInfoGetColumntbl, i);
printf("%-20s%-10s%-8i%-8i%-8i%-s\n",
OCI_ColumnGetName(col),
OCI_ColumnGetSQLType(col),
OCI_ColumnGetSize(col),
OCI_ColumnGetPrecision(col),
OCI_ColumnGetScale(col),
OCI_ColumnGetNullable(col) == TRUE ? "Y" : "N");
}
}
}

OCI_Cleanup();
return EXIT_SUCCESS;
}

Functions '"All In One"

OCILIB provides functions "all in one" with a list of variable arguments.

They reduce the number of lines of code to a minimum!

For example, OCILIB can write in only 1 line of code following actions:

• Preparing SQL
• Binding a variable
• Query Execution
• Fetch the result (1 row)

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 43

This is equivalent to the following code:

• OCI_Prepare (st, "select item from test_fetch where code =: i");


• OCI_Bind (st, "code", & code);
• OCI_execute (st);
• OCI_GetResultset (st);
• OCI_FetchNext (rs);
• OCI_GetString (rs, 1);

Which can be replaced by the following code:

• OCI_ImmediateFmt (cn, "select item from test_fetch where code =% i", code, OCI_ARG_TEXT,
name);

OCILIB offers some smart routines that take a variable number of arguments in order to minimize OCILIB
function calls and reduce the amount of code lines.

On Windows platforms, the target programming language must support the __cdecl calling convention

Note:
OCI_Immediate() and OCI_ImmediateFmt() support all OCILIB supported types for output result,
except :

• OCI_Long
• OCI_Statement If a query output result contains one of these unsupported types, the function
returns FALSE

In the parameter list, every output placeholder MUST be preceded by an integer parameter that indicates
the type of the placeholder in order to handle correctly the given pointer.

Possible values for indicating placeholders type:

• OCI_ARG_SHORT : short *
• OCI_ARG_USHORT : unsigned short *
• OCI_ARG_INT : int *
• OCI_ARG_UINT : unsigned int*
• OCI_ARG_BIGINT : big_int *
• OCI_ARG_BIGUINT : unsigned big_int *
• OCI_ARG_DOUBLE : double *
• OCI_ARG_TEXT : dtext *
• OCI_ARG_RAW : void *
• OCI_ARG_DATETIME : OCI_Date *
• OCI_ARG_LOB : OCI_Lob *
• OCI_ARG_FILE : OCI_File *
• OCI_ARG_TIMESTAMP : OCI_Timstamp *
• OCI_ARG_INTERVAL : OCI_Interval *
• OCI_ARG_OBJECT : OCI_Object *
• OCI_ARG_COLLECTION : OCI_Coll *
• OCI_ARG_REF : OCI_Ref *

For output strings and Raws, returned data is copied to the given buffer instead of returning a pointer the
real data. So theses buffers must be big enough to hold the column content. No size check is performed.

• For strings, only the real string is copied.


• For Raws, the number of bytes copied is the column size

Warning: Input parameters for formatted function only support a restricted set of datatypes!

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 44

Supported input identifiers:

• * 's' : (dtext *) : input string (quotes are added)


• * 'm' : (dtext *) : metadata string (no quotes added)
• * 't' : (OCI_Date *) : Date
• * 'p' : (OCI_Timestamp *) : timestamp
• * 'v' : (OCI_Interval *) : Interval
• * 'i' : (int) : signed 32 bits integer
• * 'u' : (unsigned int) : unsigned 32 bits integer
• * 'li' : (big_int) : signed 64 bits integer
• * 'lu' : (big_uint) : unsigned 64 bits integer
• * 'hi' : (short) : signed 16 bits integer
• * 'hu' : (unsigned short) : unsigned 16 bits integer
• * 'g' : (double ) : Numerics
• * 'r' : (OCI_Ref *) : Reference
• * 'o' : (OCI_Object *) : Object (not implemented yet)
• * 'c' : (OCI_Coll *) : collection (not implemented yet)

Other examples:

#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Resultset *rs;
int code = 1;
char name[50];
if (!OCI_Initialize(err_handler, NULL, OCI_ENV_DEFAULT))
return EXIT_FAILURE;
cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);
st = OCI_StatementCreate(cn);
/* sql format with params ----------------------------------------------- */
OCI_ExecuteStmtFmt(st, "select article from test_fetch where code = %i", code);
rs = OCI_GetResultset(st);
while (OCI_FetchNext(rs))
printf("article : %s\n", OCI_GetString(rs, 1));
/* sql immediate (parse, exec, one fetch) ------------------------------- */
OCI_Immediate(cn, "select code, article from test_fetch where code = 1",
OCI_ARG_INT, &code, OCI_ARG_TEXT, name);
printf("article : %s - code %i\n", name, code);
/* sql immediate (parse, exec, one fetch) with params ------------------- */

OCI_ImmediateFmt(cn, "select article from test_fetch where code = %i",


code, OCI_ARG_TEXT, name);
printf("article : %s\n", name);
OCI_Cleanup();
return EXIT_SUCCESS;
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 45

Optimizing performances

Some tips to optimize the performance:

• Avoid OCI_xxxFmt function() because, although very useful, they require a parsing of the SQL and
formatting of variables that can be costly if the queries are executed many times
• If a SQL statement must be repeated several times, it is preferable to prepare once with
OCI_Prepare(), bind variables with OCI_Bindxxx() and then run it as many times as desired with
OCI_Exectute()
• If possible, use tables to bind variables
• If the values affected by a DML must then be reselected, use clause "Returning into"
• Adjust the number of rows per fetch with OCI_SetFetchSize()
• Adjust the number of lines préfetchées by the server with OCI_SetPrefetchSize()
• Prefer to Lobs LONG and LONG RAW
• To retrieve values from a resultet use access by index instead of access by column name to avoid
the use of maps index / name

Using OCILIB hash tables API

OCILIB uses hash tables internally for index/name columns mapping.

OCILIB makes public its hash tables implementation public for general purpose uses.

OCI_HashTable objects manage string keys / values that can be :

• integers
• strings
• pointers

This hash table implementation:

• handle collisions
• allows multiple values per key

Internal conception

• The hash table is composed of an array of slots.


• Each slot can hold a linked list of entries (one per key)
• Each entry can hold a linked list of values

The internal hash function computes the index in the array where the entry has to be inserted/looked up.

Collisions are handled by chaining method.

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 46

#include "ocilib.h"

int main(void)
{
int i, n;
OCI_Connection *cn;
OCI_Statement *st;
OCI_Resultset *rs;
OCI_HashTable *table;
OCI_HashEntry *e;
OCI_HashValue *v;

if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT))


return EXIT_FAILURE;

cn = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);


st = OCI_StatementCreate(cn);
table = OCI_HashCreate(256, OCI_HASH_INTEGER);
/* fill the hash table with data from DB */

OCI_ExecuteStmt(st, "select code, name from products");

rs = OCI_GetResultset(st);

while (OCI_FetchNext(rs))
OCI_HashAddInt(table, OCI_GetString2(rs, "name"), OCI_GetInt2(rs, "code"));
printf("%d row(s) fetched\n", OCI_GetRowCount(rs));

/* lookup an entry */

printf("code for %s is : %d\n", "Cars", OCI_HashGetInt(table, "Cars"));

/* browse the hash table */

n = OCI_HashGetSize(table);

for (i = 0; i < n; i++)


{
e = OCI_HashGetEntry(table, i);

while (e != NULL)
{
printf (">key: '%s'\n", e->key);
v = e->values;

while (v != NULL)
{
printf ("..... value : '%i'\n", v->value.num);
v = v->next;
}

e = e->next;
}
}
/* destroy table */

OCI_HashFree(table);

OCI_Cleanup();
return EXIT_SUCCESS;
}

Using OCILIB thread API

Oracle proposes a portable implementation of Mutex and Thread objects

OCILIB implements these OCI features for portable multithreading support.

Mutexes are designed for mutual exclusion between thread in order to lock resources temporarily

Thread keys can be seen as process-wide variables that have thread-specific values. It allows creating a
unique key identified by a name (string) that can store values specific to each thread.

OCILIB exposes the types OCI_Mutex, OCI_Thread

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 47

Warning:

• OCILIB MUST be initialized with OCI_ENV_THREADED to enable threads support


• OCI_Thread relies on Oracle API which uses natives threading capabilities of the supported
platform

Using OCI_Mutex :

• On Microsoft Windows, a thread can call OCI_MutexAcquire() more than once wihtout any blocking.
Just be sure that there is an OCI_MutexRelease() for every OCI_MutexAcquire() call
• On Unixes, a thread MUST call OCI_MutexRelease() after every call to OCI_MutexAcquire() in order
to be able to call OCI_MutexAcquire() again. If not, it will be blocked...

#include "ocilib.h"
#define MAX_THREADS 50
void key_cleanup(void *str)
{
free(str);
}
void worker(OCI_Thread *thread, void *data)
{
const void *id = OCI_HandleGetThreadID(thread);
char *str = malloc(50);

sprintf(str, "thread %p !\n", id);


OCI_ThreadKeySetValue("ID", str);
/* ... do some more processing here... */

str = OCI_ThreadKeyGetValue("ID");
printf(str);
}
int main(void)
{
OCI_Thread *th[MAX_THREADS];
int i;
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT | OCI_ENV_THREADED))
return EXIT_FAILURE;
OCI_ThreadKeyCreate("ID", key_cleanup);
/* create threads */
for (i = 0; i < MAX_THREADS; i++)
{
th[i] = OCI_ThreadCreate();
OCI_ThreadRun(th[i], worker, NULL);
}
/* wait for threads and cleanup */
for (i = 0; i < MAX_THREADS; i++)
{
OCI_ThreadJoin(th[i]);
OCI_ThreadFree(th[i]);
}
OCI_Cleanup();
return EXIT_SUCCESS;
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 48

Remote database startup/shutdown

OCILIB supports Oracle 11g client features for manipulating remote Oracle instances.

Oracle instances (on the same computer or on a remote server) can be

• started with OCI_DatabaseStartup()


• Shutdown with OCI_DatabaseShutdown()

#include "ocilib.h"
int main(void)
{
OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT);
/* start remote instance */
OCI_DatabaseStartup("db",
"sys_usr",
"sys_pwd",
OCI_SESSION_SYSDBA,
OCI_DB_SPM_FULL,
OCI_DB_SPF_FORCE,
NULL);

/* shutdown remote instance */


OCI_DatabaseShutdown("db",
"sys_usr",
"sys_pwd",
OCI_SESSION_SYSDBA,
OCI_DB_SDM_FULL,
OCI_DB_SDF_ABORT);
OCI_Cleanup();
return EXIT_SUCCESS;
}

Database change notifications

OCILIB supports Oracle 10gR2 feature Database Change Notifications (DCN) also named Continuous
Query Notifications (CQN)

This feature allows a client application to register notifications when some changes are made in a
database:

• Database status changes: startup and shutdown


• Database objects changes:
 DDL changes : alter or drop actions
 DML changes : insert, delete, update actions

This feature can be really useful in applications that hold a cache of data. Instead of refreshing data
periodically by connecting to the server, the application could only refresh modified data when necessary
or perform specific tasks depending on the events. It saves application time, network traffic and can help
the design of the application logic.

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 49

The database status change notification is also interesting to be informed of instance startup / shutdown

Check Oracle documentation for more details about this feature

Note: No active database connection is required to receive the notifications as they are handled by the
Oracle client using a dedicated socket connection to the server

Database changes: The client application can be notified by any database status change (single DB or
multiple DB in a RAC environment).

Object changes: The notifications of object changes are based on the registration of a query ('select' SQL
statement).

Oracle server will notify of any changes of any object that is part of the statement result set.

Registering a statement will notify about any changes on its result set rows performed after the
registration of the query.

The query can be a simple 'select * from table' or a complex query involving many tables and/or criteria
in the where clause.

For Object changes, the notification can be at:

• At Object level: only the object name (schema + object) is given


• At row level: same that object level + ROWID of the altered row

Warning: Trying to use this features with a client/server version < 10gR2 will raise an error

#include "ocilib.h"
#ifdef _WINDOWS
#define sleep(x) Sleep(x*1000)
#endif
#define wait_for_events() sleep(5)
void event_handler(OCI_Event *event);
void error_handler(OCI_Error *err);
int main(void)
{
OCI_Connection *con;
OCI_Subscription *sub;
OCI_Statement *st;
printf("=> Initializing OCILIB in event mode...\n\n");
if (!OCI_Initialize(error_handler, NULL, OCI_ENV_EVENTS))
return EXIT_FAILURE;
printf("=> Connecting to usr@db...\n\n");
con = OCI_ConnectionCreate("db", "usr", "pwd", OCI_SESSION_DEFAULT);
OCI_SetAutoCommit(con, TRUE);
printf("=> Creating statement...\n\n");

st = OCI_StatementCreate(con);
printf("=> Creating tables...\n\n");
OCI_ExecuteStmt(st, "create table table1(code number)");
OCI_ExecuteStmt(st, "create table table2(str varchar2(10))");
printf("=> Registering subscription...\n\n");

sub = OCI_SubscriptionRegister(con, "sub-00", OCI_CNT_ALL, event_handler, 5468, 0);

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 50

printf("=> Adding queries to be notified...\n\n");

OCI_Prepare(st, "select * from table1");


OCI_SubscriptionAddStatement(sub, st);
OCI_Prepare(st, "select * from table2");
OCI_SubscriptionAddStatement(sub, st);
printf("=> Executing some DDL operation...\n\n");
OCI_ExecuteStmt(st, "alter table table1 add price number");
wait_for_events();
printf("=> Executing some DML operation...\n\n");
OCI_ExecuteStmt(st, "insert into table1 values(1, 10.5)");
OCI_ExecuteStmt(st, "insert into table2 values('shoes')");
OCI_ExecuteStmt(st, "update table1 set price = 13.5 where code = 1");
OCI_ExecuteStmt(st, "delete from table2 ");
wait_for_events();
printf("=> Droping tables...\n\n");

OCI_ExecuteStmt(st, "drop table table1");


OCI_ExecuteStmt(st, "drop table table2");
wait_for_events();
printf("=> Disconnecting from DB...\n\n");
OCI_ConnectionFree(con);

printf("=> Stopping the remote database...\n\n");


OCI_DatabaseShutdown("db", "sys", "sys",
OCI_SESSION_SYSDBA,
OCI_DB_SDM_FULL,
OCI_DB_SDF_IMMEDIATE);
wait_for_events();;

printf("=> Starting the remote database...\n\n");


OCI_DatabaseStartup("db", "sys", "sys",
OCI_SESSION_SYSDBA,
OCI_DB_SPM_FULL,
OCI_DB_SPF_FORCE,
NULL);
wait_for_events();
printf("=> Unregistering subscription...\n\n");

OCI_SubscriptionUnregister(sub);
printf("=> Cleaning up OCILIB resources...\n\n");
OCI_Cleanup();
printf("=> Done...\n\n");
return EXIT_SUCCESS;
}
void error_handler(OCI_Error *err)
{
int err_type = OCI_ErrorGetType(err);
const char *err_msg = OCI_ErrorGetString(err);
printf("** %s - %s\n", err_type == OCI_ERR_WARNING ? "Warning" : "Error", err_msg);
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 51

void event_handler(OCI_Event *event)


{
unsigned int type = OCI_EventGetType(event);
unsigned int op = OCI_EventGetOperation(event);
OCI_Subscription *sub = OCI_EventGetSubscription(event);
printf("** Notification : %s\n\n", OCI_SubscriptionGetName(sub));
printf("...... Database : %s\n", OCI_EventGetDatabase(event));
switch (type)
{
case OCI_ENT_STARTUP:
printf("...... Event : Startup\n");
break;
case OCI_ENT_SHUTDOWN:
printf("...... Event : Shutdown\n");
break;
case OCI_ENT_SHUTDOWN_ANY:
printf("...... Event : Shutdown any\n");
break;
case OCI_ENT_DROP_DATABASE:
printf("...... Event : drop database\n");
break;
case OCI_ENT_DEREGISTER:
printf("...... Event : deregister\n");
break;
case OCI_ENT_OBJECT_CHANGED:
printf("...... Event : object changed\n");
printf("........... Object : %s\n", OCI_EventGetObject(event));
switch (op)
{
case OCI_ONT_INSERT:
printf("........... Action : insert\n");
break;
case OCI_ONT_UPDATE:
printf("........... Action : update\n");
break;
case OCI_ONT_DELETE:
printf("........... Action : delete\n");
break;
case OCI_ONT_ALTER:
printf("........... Action : alter\n");
break;
case OCI_ONT_DROP:
printf("........... Action : drop\n");
break;
}
if (op < OCI_ONT_ALTER)
printf("........... Rowid : %s\n", OCI_EventGetRowid(event));
break;
}
printf("\n");
}

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 52

Going deeper in OCI: direct use of OCI handles

OCILIB conception was focused on a full but closed encapsulation of OCI.

All OCI headers, datatypes, prototypes are imported internally (linkage or runtime import).

OCILIB public interface exposes only ISO C scalar types and OCILIB objects

OCI is a wide and rich API that can deals with hundreds of options!

OCILIB tries to implements most of it. But, sometimes in really specific contexts, it might be necessary to
directly call OCI APIs in order to use uncovered OCI functionalities or options

OCILIB proposes now a set of functions to retrieve its internal OCI handles

Warning:

• OCILIB author strongly advises against the use of internal handles, unless there is no other way to
accomplish the task
• Using these handles for direct application calls to OCI might lead to OCILIB instability or crash if
handles are incorrectly used!

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 53

13. Annexes

GNU Free Documentation License

GNU Free Documentation License


Version 1.3, 3 November 2008

Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
<http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

0. PREAMBLE

The purpose of this License is to make a manual, textbook, or other


functional and useful document "free" in the sense of freedom: to
assure everyone the effective freedom to copy and redistribute it,
with or without modifying it, either commercially or noncommercially.
Secondarily, this License preserves for the author and publisher a way
to get credit for their work, while not being considered responsible
for modifications made by others.

This License is a kind of "copyleft", which means that derivative


works of the document must themselves be free in the same sense. It
complements the GNU General Public License, which is a copyleft
license designed for free software.

We have designed this License in order to use it for manuals for free
software, because free software needs free documentation: a free
program should come with manuals providing the same freedoms that the
software does. But this License is not limited to software manuals;
it can be used for any textual work, regardless of subject matter or
whether it is published as a printed book. We recommend this License
principally for works whose purpose is instruction or reference.

1. APPLICABILITY AND DEFINITIONS

This License applies to any manual or other work, in any medium, that
contains a notice placed by the copyright holder saying it can be
distributed under the terms of this License. Such a notice grants a
world-wide, royalty-free license, unlimited in duration, to use that
work under the conditions stated herein. The "Document", below,
refers to any such manual or work. Any member of the public is a
licensee, and is addressed as "you". You accept the license if you
copy, modify or distribute the work in a way requiring permission
under copyright law.

A "Modified Version" of the Document means any work containing the

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 54

Document or a portion of it, either copied verbatim, or with


modifications and/or translated into another language.

A "Secondary Section" is a named appendix or a front-matter section of


the Document that deals exclusively with the relationship of the
publishers or authors of the Document to the Document's overall
subject (or to related matters) and contains nothing that could fall
directly within that overall subject. (Thus, if the Document is in
part a textbook of mathematics, a Secondary Section may not explain
any mathematics.) The relationship could be a matter of historical
connection with the subject or with related matters, or of legal,
commercial, philosophical, ethical or political position regarding
them.

The "Invariant Sections" are certain Secondary Sections whose titles


are designated, as being those of Invariant Sections, in the notice
that says that the Document is released under this License. If a
section does not fit the above definition of Secondary then it is not
allowed to be designated as Invariant. The Document may contain zero
Invariant Sections. If the Document does not identify any Invariant
Sections then there are none.

The "Cover Texts" are certain short passages of text that are listed,
as Front-Cover Texts or Back-Cover Texts, in the notice that says that
the Document is released under this License. A Front-Cover Text may
be at most 5 words, and a Back-Cover Text may be at most 25 words.

A "Transparent" copy of the Document means a machine-readable copy,


represented in a format whose specification is available to the
general public, that is suitable for revising the document
straightforwardly with generic text editors or (for images composed of
pixels) generic paint programs or (for drawings) some widely available
drawing editor, and that is suitable for input to text formatters or
for automatic translation to a variety of formats suitable for input
to text formatters. A copy made in an otherwise Transparent file
format whose markup, or absence of markup, has been arranged to thwart
or discourage subsequent modification by readers is not Transparent.
An image format is not Transparent if used for any substantial amount
of text. A copy that is not "Transparent" is called "Opaque".

Examples of suitable formats for Transparent copies include plain


ASCII without markup, Texinfo input format, LaTeX input format, SGML
or XML using a publicly available DTD, and standard-conforming simple
HTML, PostScript or PDF designed for human modification. Examples of
transparent image formats include PNG, XCF and JPG. Opaque formats
include proprietary formats that can be read and edited only by
proprietary word processors, SGML or XML for which the DTD and/or
processing tools are not generally available, and the
machine-generated HTML, PostScript or PDF produced by some word
processors for output purposes only.

The "Title Page" means, for a printed book, the title page itself,
plus such following pages as are needed to hold, legibly, the material
this License requires to appear in the title page. For works in
formats which do not have any title page as such, "Title Page" means
the text near the most prominent appearance of the work's title,
preceding the beginning of the body of the text.

The "publisher" means any person or entity that distributes copies of


the Document to the public.

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 55

A section "Entitled XYZ" means a named subunit of the Document whose


title either is precisely XYZ or contains XYZ in parentheses following
text that translates XYZ in another language. (Here XYZ stands for a
specific section name mentioned below, such as "Acknowledgements",
"Dedications", "Endorsements", or "History".) To "Preserve the Title"
of such a section when you modify the Document means that it remains a
section "Entitled XYZ" according to this definition.

The Document may include Warranty Disclaimers next to the notice which
states that this License applies to the Document. These Warranty
Disclaimers are considered to be included by reference in this
License, but only as regards disclaiming warranties: any other
implication that these Warranty Disclaimers may have is void and has
no effect on the meaning of this License.

2. VERBATIM COPYING

You may copy and distribute the Document in any medium, either
commercially or noncommercially, provided that this License, the
copyright notices, and the license notice saying this License applies
to the Document are reproduced in all copies, and that you add no
other conditions whatsoever to those of this License. You may not use
technical measures to obstruct or control the reading or further
copying of the copies you make or distribute. However, you may accept
compensation in exchange for copies. If you distribute a large enough
number of copies you must also follow the conditions in section 3.

You may also lend copies, under the same conditions stated above, and
you may publicly display copies.

3. COPYING IN QUANTITY

If you publish printed copies (or copies in media that commonly have
printed covers) of the Document, numbering more than 100, and the
Document's license notice requires Cover Texts, you must enclose the
copies in covers that carry, clearly and legibly, all these Cover
Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
the back cover. Both covers must also clearly and legibly identify
you as the publisher of these copies. The front cover must present
the full title with all words of the title equally prominent and
visible. You may add other material on the covers in addition.
Copying with changes limited to the covers, as long as they preserve
the title of the Document and satisfy these conditions, can be treated
as verbatim copying in other respects.

If the required texts for either cover are too voluminous to fit
legibly, you should put the first ones listed (as many as fit
reasonably) on the actual cover, and continue the rest onto adjacent
pages.

If you publish or distribute Opaque copies of the Document numbering


more than 100, you must either include a machine-readable Transparent
copy along with each Opaque copy, or state in or with each Opaque copy
a computer-network location from which the general network-using
public has access to download using public-standard network protocols
a complete Transparent copy of the Document, free of added material.
If you use the latter option, you must take reasonably prudent steps,
when you begin distribution of Opaque copies in quantity, to ensure

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 56

that this Transparent copy will remain thus accessible at the stated
location until at least one year after the last time you distribute an
Opaque copy (directly or through your agents or retailers) of that
edition to the public.

It is requested, but not required, that you contact the authors of the
Document well before redistributing any large number of copies, to
give them a chance to provide you with an updated version of the
Document.

4. MODIFICATIONS

You may copy and distribute a Modified Version of the Document under
the conditions of sections 2 and 3 above, provided that you release
the Modified Version under precisely this License, with the Modified
Version filling the role of the Document, thus licensing distribution
and modification of the Modified Version to whoever possesses a copy
of it. In addition, you must do these things in the Modified Version:

A. Use in the Title Page (and on the covers, if any) a title distinct
from that of the Document, and from those of previous versions
(which should, if there were any, be listed in the History section
of the Document). You may use the same title as a previous version
if the original publisher of that version gives permission.
B. List on the Title Page, as authors, one or more persons or entities
responsible for authorship of the modifications in the Modified
Version, together with at least five of the principal authors of the
Document (all of its principal authors, if it has fewer than five),
unless they release you from this requirement.
C. State on the Title page the name of the publisher of the
Modified Version, as the publisher.
D. Preserve all the copyright notices of the Document.
E. Add an appropriate copyright notice for your modifications
adjacent to the other copyright notices.
F. Include, immediately after the copyright notices, a license notice
giving the public permission to use the Modified Version under the
terms of this License, in the form shown in the Addendum below.
G. Preserve in that license notice the full lists of Invariant Sections
and required Cover Texts given in the Document's license notice.
H. Include an unaltered copy of this License.
I. Preserve the section Entitled "History", Preserve its Title, and add
to it an item stating at least the title, year, new authors, and
publisher of the Modified Version as given on the Title Page. If
there is no section Entitled "History" in the Document, create one
stating the title, year, authors, and publisher of the Document as
given on its Title Page, then add an item describing the Modified
Version as stated in the previous sentence.
J. Preserve the network location, if any, given in the Document for
public access to a Transparent copy of the Document, and likewise
the network locations given in the Document for previous versions
it was based on. These may be placed in the "History" section.
You may omit a network location for a work that was published at
least four years before the Document itself, or if the original
publisher of the version it refers to gives permission.
K. For any section Entitled "Acknowledgements" or "Dedications",
Preserve the Title of the section, and preserve in the section all
the substance and tone of each of the contributor acknowledgements
and/or dedications given therein.
L. Preserve all the Invariant Sections of the Document,

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 57

unaltered in their text and in their titles. Section numbers


or the equivalent are not considered part of the section titles.
M. Delete any section Entitled "Endorsements". Such a section
may not be included in the Modified Version.
N. Do not retitle any existing section to be Entitled "Endorsements"
or to conflict in title with any Invariant Section.
O. Preserve any Warranty Disclaimers.

If the Modified Version includes new front-matter sections or


appendices that qualify as Secondary Sections and contain no material
copied from the Document, you may at your option designate some or all
of these sections as invariant. To do this, add their titles to the
list of Invariant Sections in the Modified Version's license notice.
These titles must be distinct from any other section titles.

You may add a section Entitled "Endorsements", provided it contains


nothing but endorsements of your Modified Version by various
parties--for example, statements of peer review or that the text has
been approved by an organization as the authoritative definition of a
standard.

You may add a passage of up to five words as a Front-Cover Text, and a


passage of up to 25 words as a Back-Cover Text, to the end of the list
of Cover Texts in the Modified Version. Only one passage of
Front-Cover Text and one of Back-Cover Text may be added by (or
through arrangements made by) any one entity. If the Document already
includes a cover text for the same cover, previously added by you or
by arrangement made by the same entity you are acting on behalf of,
you may not add another; but you may replace the old one, on explicit
permission from the previous publisher that added the old one.

The author(s) and publisher(s) of the Document do not by this License


give permission to use their names for publicity for or to assert or
imply endorsement of any Modified Version.

5. COMBINING DOCUMENTS

You may combine the Document with other documents released under this
License, under the terms defined in section 4 above for modified
versions, provided that you include in the combination all of the
Invariant Sections of all of the original documents, unmodified, and
list them all as Invariant Sections of your combined work in its
license notice, and that you preserve all their Warranty Disclaimers.

The combined work need only contain one copy of this License, and
multiple identical Invariant Sections may be replaced with a single
copy. If there are multiple Invariant Sections with the same name but
different contents, make the title of each such section unique by
adding at the end of it, in parentheses, the name of the original
author or publisher of that section if known, or else a unique number.
Make the same adjustment to the section titles in the list of
Invariant Sections in the license notice of the combined work.

In the combination, you must combine any sections Entitled "History"


in the various original documents, forming one section Entitled
"History"; likewise combine any sections Entitled "Acknowledgements",
and any sections Entitled "Dedications". You must delete all sections
Entitled "Endorsements".

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 58

6. COLLECTIONS OF DOCUMENTS

You may make a collection consisting of the Document and other


documents released under this License, and replace the individual
copies of this License in the various documents with a single copy
that is included in the collection, provided that you follow the rules
of this License for verbatim copying of each of the documents in all
other respects.

You may extract a single document from such a collection, and


distribute it individually under this License, provided you insert a
copy of this License into the extracted document, and follow this
License in all other respects regarding verbatim copying of that
document.

7. AGGREGATION WITH INDEPENDENT WORKS

A compilation of the Document or its derivatives with other separate


and independent documents or works, in or on a volume of a storage or
distribution medium, is called an "aggregate" if the copyright
resulting from the compilation is not used to limit the legal rights
of the compilation's users beyond what the individual works permit.
When the Document is included in an aggregate, this License does not
apply to the other works in the aggregate which are not themselves
derivative works of the Document.

If the Cover Text requirement of section 3 is applicable to these


copies of the Document, then if the Document is less than one half of
the entire aggregate, the Document's Cover Texts may be placed on
covers that bracket the Document within the aggregate, or the
electronic equivalent of covers if the Document is in electronic form.
Otherwise they must appear on printed covers that bracket the whole
aggregate.

8. TRANSLATION

Translation is considered a kind of modification, so you may


distribute translations of the Document under the terms of section 4.
Replacing Invariant Sections with translations requires special
permission from their copyright holders, but you may include
translations of some or all Invariant Sections in addition to the
original versions of these Invariant Sections. You may include a
translation of this License, and all the license notices in the
Document, and any Warranty Disclaimers, provided that you also include
the original English version of this License and the original versions
of those notices and disclaimers. In case of a disagreement between
the translation and the original version of this License or a notice
or disclaimer, the original version will prevail.

If a section in the Document is Entitled "Acknowledgements",


"Dedications", or "History", the requirement (section 4) to Preserve
its Title (section 1) will typically require changing the actual
title.

9. TERMINATION

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 59

You may not copy, modify, sublicense, or distribute the Document


except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense, or distribute it is void, and
will automatically terminate your rights under this License.

However, if you cease all violation of this License, then your license
from a particular copyright holder is reinstated (a) provisionally,
unless and until the copyright holder explicitly and finally
terminates your license, and (b) permanently, if the copyright holder
fails to notify you of the violation by some reasonable means prior to
60 days after the cessation.

Moreover, your license from a particular copyright holder is


reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, receipt of a copy of some or all of the same material does
not give you any rights to use it.

10. FUTURE REVISIONS OF THIS LICENSE

The Free Software Foundation may publish new, revised versions of the
GNU Free Documentation License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in
detail to address new problems or concerns. See
http://www.gnu.org/copyleft/.

Each version of the License is given a distinguishing version number.


If the Document specifies that a particular numbered version of this
License "or any later version" applies to it, you have the option of
following the terms and conditions either of that specified version or
of any later version that has been published (not as a draft) by the
Free Software Foundation. If the Document does not specify a version
number of this License, you may choose any version ever published (not
as a draft) by the Free Software Foundation. If the Document
specifies that a proxy can decide which future versions of this
License can be used, that proxy's public statement of acceptance of a
version permanently authorizes you to choose that version for the
Document.

11. RELICENSING

"Massive Multiauthor Collaboration Site" (or "MMC Site") means any


World Wide Web server that publishes copyrightable works and also
provides prominent facilities for anybody to edit those works. A
public wiki that anybody can edit is an example of such a server. A
"Massive Multiauthor Collaboration" (or "MMC") contained in the site
means any set of copyrightable works thus published on the MMC site.

"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0


license published by Creative Commons Corporation, a not-for-profit
corporation with a principal place of business in San Francisco,
California, as well as future copyleft versions of that license

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3
Developing C/C++ Oracle applications with OCILIB 60

published by that same organization.

"Incorporate" means to publish or republish a Document, in whole or in


part, as part of another Document.

An MMC is "eligible for relicensing" if it is licensed under this


License, and if all works that were first published under this License
somewhere other than this MMC, and subsequently incorporated in whole or
in part into the MMC, (1) had no cover texts or invariant sections, and
(2) were thus incorporated prior to November 1, 2008.

The operator of an MMC Site may republish an MMC contained in the site
under CC-BY-SA on the same site at any time before August 1, 2009,
provided the MMC is eligible for relicensing.

Copyright © 2008-2010 Vincent Rogier – http://www.ocilib.net - Document under GNU Free Documentation License v1.3

You might also like