Professional Documents
Culture Documents
C/C++
ORACLE APPLICATIONS
WITH
How to
easily and efficiently program
Oracle effective applications
in C/C++
DEVELOPING
C/C++
ORACLE APPLICATIONS
WITH
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 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
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
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
Introduction
OCILIB is an open source and cross platform Oracle library that delivers really efficient and reliable access
to Oracle databases.
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. ...).
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 ...).
• 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):
Documentation
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
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 versions of Oracle (clients and servers) have been validated:
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.
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
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)
On Microsoft Windows, 32bits and 64bits (x86) DLLs are provided and can be easily recompiled.
[x] is the compiled version of OCILIB ('a' -> ANSI, 'w' -> Unicode, 'm' -> Mixed)
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:
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:
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
- 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:
If all OCILIB import libraries builds (ocilib[x].lib) are accessible to the linker, then you must specify which
one to use with:
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 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.
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
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 :
Additional 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:
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:
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.
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.
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
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.
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;
}
• 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
• Oracle connection string (Service name, full TNS connection string or an easy connect string)
• Oracle user
• Oracle user password
• The session 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
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
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.
When an exception is raised, OCILIB calls the error handler provided by the application. The prototype of
the callback to provide is:
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
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;
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
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
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:
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:
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 ':'.
• 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
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',
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);
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);
/* ... */
However, Oracle supports "bulks operations" (see Chapter 6) that allows host arrays binding and thus a
major increase of performance.
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()
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.
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;
}
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);
}
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_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:
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
Stored procedures/functions calls, blocks declarations are done like regular SQL calls using
OCI_Prepare(), OCI_Execute(), OCI_ExecuteStmt() and OCI_ExecuteStmtFmt() functions.
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);
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
int main(void)
{
OCI_Connection *cn;
OCI_Statement *st;
const dtext *p;
return EXIT_SUCCESS;
}
OCILIB supports the Oracle feature 'Returning into' for DML statements.
'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;
}
• 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:
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.
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.
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);
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
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).
• An OCI_Lob C type
• A set of really easy APIs to manipulate OCI_Lob objects
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:
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
#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);
}
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
#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);
return EXIT_SUCCESS;
}
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.
• 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
#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_File *file;
char buffer[256];
int n;
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),
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.
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"
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);
OCI_LongFree(lg);
OCI_Commit(cn);
}
/* FETCHING LONGS -------------------------------------------- */
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
Date handles
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);
return EXIT_SUCCESS;
}
Timestamp handles
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
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
OCILIB implements Oracle Named types (user types and built-in types) through the OCI_Object type.
In order to manipulate objects attributes, OCILIB proposes a set of functions to get/set properties for
various supported types.
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:
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
#include "ocilib.h"
int main()
{
OCI_Connection *cn;
OCI_Statement *st;
OCI_Resultset *rs;
OCI_Object *prod;
OCI_Date *date;
int qte;
qte = 356;
OCI_DateSysDate(date);
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;
rs = OCI_GetResultset(st);
while (OCI_FetchNext(rs))
{
prod = OCI_GetObject(rs, 1);
qte = OCI_GeInt(rs, 2);
date = OCI_GetDate(rs, 3);
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
Collections types
• 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:
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;
OCI_IterFree(iter);
OCI_CollFree(coll);
rs = OCI_GetResultset(st);
while (OCI_FetchNext(rs))
{
/* iterate the collection using an iterator */
iter = OCI_IterCreate(coll);
elem = OCI_IterGetNext(iter);
rs = OCI_GetResultset(st);
while (OCI_FetchNext(rs))
{
coll = OCI_GetColl(rs, 2);
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
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:
All scalar datatypes (numerics, characters and date/time), including LOBs and LONG types are supported
“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.”
“The direct path load interface has the following limitations which are the same as SQL*Loader:
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)
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"
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];
OCI_DirPathSetBufferSize(dp, 64000);
OCI_DirPathSetNoLog(dp, TRUE);
OCI_DirPathSetParallel(dp, TRUE);
OCI_DirPathPrepare(dp);
nb_rows = OCI_DirPathGetMaxRows(dp);
OCI_DirPathConvert(dp);
OCI_DirPathLoad(dp);
/* commits changes */
OCI_DirPathFinish(dp);
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
#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;
}
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
• 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.
• 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.
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
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 ------------------- */
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
• 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
OCILIB makes public its hash tables implementation public for general purpose uses.
• integers
• strings
• pointers
• handle collisions
• allows multiple values per key
Internal conception
The internal hash function computes the index in the array where the entry has to be inserted/looked up.
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;
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 */
n = OCI_HashGetSize(table);
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;
}
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.
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:
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);
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
OCILIB supports Oracle 11g client features for manipulating remote Oracle instances.
#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);
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:
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
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.
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");
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
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
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
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
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
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.
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.
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
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.
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.
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
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.
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
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.
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
8. TRANSLATION
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
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.
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.
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/.
11. RELICENSING
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
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