OTL 4.0, How to compile OTL

How to compile OTL

OTL 4.0 is an integrated library which contains a template stream framework and OTL-adapters for the OCI7, OCI8, OCI8i, OCI9i, OCI10g, ODBC 2.5, ODBC 3.x, DB2 CLI, and Informix CLI. The following macro definitions (#define's) need to be used in order to compile OTL for each type of the underlying database API from the list above:

#define Name Explanation
OTL_DB2_CLI for DB2 Call Level Interface (CLI)
OTL_ODBC_
ENTERPRISEDB

for Enterprise DB ODBC provider. Enterprise DB is a variant of PostreSQL that was made compatible with Oracle (up to some extent) and commecially available.
OTL_INFORMIX_CLI
for Informix Call Level Interface for Unix (when  OTL_ODBC_UNIX is enabled).
OTL_IODBC_BSD for ODBC on BSD Unix, when iODBC package is used
OTL_ODBC for ODBC
OTL_ODBC_MSSQL_2005
Microsoft SQL Server 2005 requires special treatment when VARCHAR(MAX), VARBINARY(MAX), and NVARCHAR(MAX) are used. MS SQL 2005's Native SQL Client (SNAC) handles the new XXX(MAX) data types in a different way, compared with TEXT, NTEXT, and IMAGE data types. If the XXX(MAX) types are not used, #define OTL_ODBC can be used. Otherwise, this new #define OTL_ODBC_MSSQL_2005 should be used.
OTL_ODBC_
MSSQL_2008

MS SQL Server 2008 has new features like datetime2, date, time, filestream based VARBINARY(MAX), etc. This #define enables OTL support for most of the new features.
OTL_ODBC_
MULTI_MODE

This #define should be used when there is a need to connect via ODBC to more than one database type from the same time. For more detail see otl_connect::set_connection_mode(), and OTL example 675.
OTL_ODBC_MYSQL for MyODBC/MySQL. The difference between OTL_ODBC_MYSQL and OTL_ODBC is that transactional ODBC function calls are turned off for OTL_ODBC_MYSQL, since MySQL does not have transactions, unless innoDB table type is used.. This #define should only used with the MyODBC 2.5, which is very old at this point in time. See MySQL based OTL code examples for more detail.
OTL_ODBC_
POSTGRESQL

PostgreSQL ODBC can be used with the standard #define OTL_ODBC. However, PostgreSQL has at least two ODBC drivers,  and some of them should be used with #define OTL_ODBC_POSTGRESQL. The following list specifies the differences between #define OTL_ODBC and #define OTL_ODBC_POSTGRESQL in more detail:
  • Linux
    • psqlodbc.so,  psqlodbcw.so should be used with #define OTL_ODBC_POSTGRESQL
    • libodbcpsql.so should be used with #define OTL_ODBC
  • Solaris
    • libodbcpsql.so should be used with #define OTL_ODBC_POSTGRESQL
  • Windows
    • pgsqlodbc30a.dll, pgsqlodbc35w.dll should be used with #define OTL_ODBC_POSTGRESQL
OTL_ODBC_
TIMESTEN_UNIX

for TimesTen in Unix/Linux. TimesTen supports ODBC. Unlike many other database systems, where ODBC API support may be much slower than the proprietary interface, ODBC is the native TimesTen interface that operates directly with the database engine. TimesTen ODBC driver has the following extensions that are available through OTL:
  • the named notation for bind variables / placeholders
  • TT_PRFEFETCH_COUNT ([0..128] range)

See "how to compile TimesTen in Linux/Unix" for more detail.
OTL_ODBC_
TIMESTEN_WIN
for TimesTen in Windows. TimesTen supports ODBC. Unlike many other database systems, where ODBC API support may be much slower than the proprietary interface, ODBC is the native TimesTen interface that operates directly with the database engine. ODBC driver has the following extensions that are available through OTL:
  • the named notation for bind variables / placeholders
  • TT_PRFEFETCH_COUNT ([1..128] range)
See how to compile TimesTen in Windows for more detail.
OTL_ODBC_UNIX for ODBC bridges in Unix
OTL_ODBC_zOS for ODBC on IBM zOS.
OTL_ODBC_XTG_IBASE6 for Interbase 6.x via XTG Systems'  ODBC driver. The reason for introducing this #define is that the ODBC driver is the only Open Source ODBC driver for Interbase. Other drivers, like Easysoft's ODBC for Interbase, are commercial products, and it beats the purpose of using Interbase, as an Open Source.database server.
OTL_ORA7 for OCI7
OTL_ORA8 for OCI8
OTL_ORA8I for OCI8i
OTL_ORA9I for OCI9i. All code that compiles and works under #define OTL_ORA7, OTL_ORA8, and OTL_ORA8I, should work when OTL_ORA9I is used
OTL_ORA10G
for OCI10g. All code that compiles and works  under #define OTL_ORA7, OTL_ORA8, OTL_ORA8I, OTL_ORA9I, should work with OTL_ORA10G.
OTL_ORA10G_R2 for OCI10g, Release 2 (Oracle 10.2). All code that compiles and works  under #define OTL_ORA7, OTL_ORA8, OTL_ORA8I, OTL_ORA9I, and OTL_ORA10G should work with OTL_ORA10G_R2 .
OTL_ORA11G
for OCI11g Release 1 (Oracle 11.1). All code that compiles and works under #define OTL_ORA7, OTL_ORA8, OTL_ORA8I, OTL_ORA9I, OTL_ORA10G, and OTL_ORA10G_R2 should work with OTL_ORA11G..


There are several extra macro definitions which control compilation of the OTL header file:

#define
Explanation
OTL_ACE  (the same as #define OTL_STL, only for use with Adaptive Communication Environment (ACE)). This #defines makes OTL compile with ACE. Most features of OTL, which require #define OTL_STL to be on, compile with ACE, except for otl_output_iterator, otl_input_iterator., and the STL vector based PL/SQL table container classes (otl_XXX_vec). OTL stream iterators were not implemented for ACE since the concept of stream iterators is not present in ACE. Same with with the otl_XXX_vec: vectors are not implemented in ACE. ACE has only dynamic arrays with dynamically defined sizes.
OTL_ADD
_NULL
_TERMINATOR
_TO_STRING
_SIZE
.
This #define enables the addition of one byte / Unicode character to the size of a string buffer, when the buffer gets allocated on the program's heap. This alleviates the burden of remembering that an extra byte / Unicode character needs to be added to the string buffer size to accomodate the string's NULL terminator.
OTL_ANSI_CPP  for turning on ANSI C++ compliance mode: ANSI C++ typecasts (static_cast<>, const_cast<>, reinterpret_cast<> instead of C-style typecasts), optional function throw clauses, typename instead of class keywords in class type template class parameters, etc.
OTL_BIGINT  This #define enables support for bigint (64-bit signed integer) bind variables by specifynig a 64-bit signed integer datatype name, for example:
#define OTL_BIGINT __int64 // VC++, Borland C++
or
#define OTL_BIGINT long long // GNU C++

ODBC and DB2-CLI support 64-bit integers natively, so does OTL. No 32-bit OCI (OCI7,OCI8, OCI8i, OCI9i, OCI10g, OCI11g) supports 64-bit integers, so OTL has to emulate this type of bind variables via strings (char[XXX]). OTL allocates and  binds a string variable with a placeholder that is defined as <bigint>.

In case if OTL_BIGINT under a 32-bit C++ compiler, and one of the OTL_ORAxx #defines are defined together, the following two defines also need to be enabled: OTL_BIGINT_TO_STR, OTL_STR_TO_BIGINT.

In 64-bit OCIs (OTL/ORAXXX) on LP64 platformts, #define OTL_ORA_MAP_BIGINT_TO_LONG can be used to map <bigint> to 64-bit longs on LP64 platforms, which is more efficient than the char[XXX] OCI binding for <bigint>.
OTL_BIGINT
_TO_STR(n,str)
This #define is required when OTL_BIGINT is enabled and when one of OTL_ORAxx #defines is enabled, in order to support OTL internal bigint-to-string conversion. This #define is supposed to provide bigint-to-string conversion code that is most probably C++ compiler specific (because 64-bit ints are not part of the ANSI C++ standard), for example:
#if defined(_MSC_VER) // VC++

#define OTL_BIGINT __int64

#define OTL_STR_TO_BIGINT(str,n) \
{ \
n=_atoi64(str); \
}

#define OTL_BIGINT_TO_STR(n,str) \
{ \
_i64toa(n,str,10); \
}
#endif

OTL_BIND_VAR
_STRICT_
TYPE_
CHECKING_ON
 
This #define enables "bind variable strict type checking", that is, typos in bind variable data type declarations get checked strictly. OTL, for performance, checks out as few characters as possible in a bind variable declaration, in order to recognize a legitimate data type declaration. Sometimes, it results in some parts of unrecognized declaration to be left as is, which, in its turn, causes a database runtime error, typically, an SQL statement parse error. In most cases, it's okay, no trouble whatsoever. In very rare cases, depending on a concrete release of a database API, on a specific platform, it causes a program core dump / crash.

It is recommended to use this #define as part of the "Debug mode", in order to sort out errors of this kind. Then, when compiling in "Release mode", the #define could be dropped.
OTL_DB2_CLI_
MAP_LONG_
VARCHAR_TO
_VARCHAR
This #define works in a combination with #define OTL_DB2_CLI. It should be used in the case of the DB2 CLI on the client side and the DB2 OS/390 on the server side, because all VARCHAR table columns that are >= 255 bytes get reported by the DB2 CLI as SQL_LONG_VARCHARs (normally reserved for DB2 CLOB columns). In DB2 UDB distributed (non-OS/390 flavor), all VARCHARs get reported as DB2 CLI's SQL_VARCHARs. When #define OTL_DB2_MAP_LONG_VARCHAR_TO_VARCHAR is defined, all VARCHAR table colunms, which are shorter (<=) than the value defined by the #define, get mapped to SQL_VARCHAR, even though the DB2 CLI reports the columns as SQL_LONG_VARCHARs. For example:

#define OTL_DB2_CLI
#define OTL_DB2_CLI_MAP_LONG_VARCHAR_TO_VARCHAR 4000
#include <otlv4.h>

In this example, all VARCHAR table columns, that are <= 4000 bytes, will be mapped to SQL_VARCHAR, even though the client code connects to a DB2 OS/390 database, and the client DB2 CLI reports the columns as SQL_LONG_VARCHARs. This
kind of datatype mapping happens only on SELECT statements, or stored procedures that return a result set.
OTL_
DEFAULT
_CHAR_
NULL_TO_VAL
When this #define is set to a char value, in the case of a NULL, returned from the database, OTL assigns the value to the variable that is used in operator>>(char&), or in operator(unsigned char&). At the same time, otl_stream::is_null() can be used to check for NULL. This default value is more of a convenience than necessity.
OTL_
DEFAULT
_NUMERIC_
NULL_TO_VAL
When this #define is set to a numeric value, in the case of a NULL returned from the database, OTL assigns the value to the variable that is used in operator>>(numeric_type&).  At the same time, otl_stream::is_null() can be used to check for NULL. This default value is more of a convenience than necessity.
OTL_DEFAULT
_DATETIME
_NULL_TO_VAL 
When this #define is set to a value of otl_datetime datatype, in the case of a NULL, returned from the database, OTL assigns the value to to the variable that is used in operator>>(otl_datetime&). At the same time, otl_stream::is_null() can be used to check for NULL. This default value is more of a convenience than necessity.
OTL_DEFAULT
_STRING
_NULL_TO_VAL

When this #define is set to a string value, in the case of a NULL, returned from the database., OTL assigns the value to the variable that is used in operator>>(std::string&), or in operator>>(ACE_TString&), or in a string class, defined by #define USER_DEFINED_STRING_CLASS: opartor>>(USER_DEFINED_STRING_CLASS&). Also, OTL assigns the value to the variable that is used in operator>>(char*), or in opartor>>(unsigned char*). At the same time, otl_stream::is_null() can be used to check for NULL. This default vaue is more of a convenience than necessity.
OTL_DESTRUCTORS_
DO_NOT_THROW
Top C++ experts say that "throwing destructors" are bad. OTL throws execptions from destructors by default in order to communicate database errors via otl_exceptions. OTL also makes the maximum effort (see #define OTL_UNCAUGHT_EXCEPTION_ON for more detail) to detect the stack unwinding situation and not to throw exceptions from destructors in that case, because that would result in an immediate program abort. #define OTL_DESTRUCTORS_DO_NOT_THROW enables try/catch blocks to prevent OTL destructors from throwing exceptions. See this for more detail on the topic. It's strongly recommended, if you enable this #define, to make sure that every single instance of otl_connect, otl_stream, otl_lob_stream releases its underlying resources when it goes out of scope. In the worst case, information about a database error may be lost.

OTL_ENABLE_
MSSQL_MARS
MS SQL SQL 2005 and 2008 support the Multiple Active Result Sets (MARS), which is not enabled by default. In order for MARS to be enabled, an ODBC function call needs to be made. This #define enables the corresponding ODBC function call.
OTL_EXCEPTION_
IS_DERIVED_FROM_
STD_EXCEPTION

This #define is a shortcut for the following:

#define OTL_EXCEPTION_DERIVED_FROM std::exception
#define OTL_EXCEPTION_HAS_MEMBERS                       \
    virtual const char* what() const                    \
    {                                                   \
      return reinterpret_cast<const char*>(msg);        \
    }

It means that otl_exception is derived from std::exception.
OTL_EXCEPTION
_DERIVED_FROM
 
This #define allows the otl_exception class to be included into already exsisting hierarchy of exception classes. The #define should specify a name of already existing class, which is used as part of the exception class hierarchy. The STL exception class hiararchy is a good example. otl_exception can be derived from one of the classes in the hierarchy, so that a catch block, that catches exception of the base class, will be able to catch exceptions of the otl_exception class. In the OTL header file, in case if this #define is defined, the class, defined in the #define, will be specified as a base class for the otl_exception class.
OTL_EXCEPTION_
ENABLE_
ERROR_
OFFSET
This #define enables the so called SQL Statement Parse Error Offset, and it is available for OTL/OCIx only. When an otl_exception gets thrown, and it has otl_exception::stm_text field populated, the parse error offset will point to the actual position of the SQL error.
OTL_EXCEPTION
_HAS_MEMBERS
This #define allows the user to define new member functions or data members in the otl_exception class. The OTL header file checks out whether this #define is defined, and then the body of the #define gets included textually into the body of the otl_exception class. This simple technique allows the otl_exception class to have new members. This #define can be used in a combination with #define OTL_EXCEPTION_DERIVED_FROM.
OTL_EXPLICIT
_NAMESPACES

(for turning on namespaces)
OTL_EXCEPTION_
STM_TEXT_
SIZE

This #define specifies a new size for the otl_exception::stm_text buffer. By default, it's 2048 bytes, that is, the actual otl_exception will contain only 2047 first bytes of the SQL statement, associated with the exception. If more bytes of the SQL statement text is needed, the #define can come handy.This #define can be used in a combination with #define OTL_EXCEPTION_ENABLE_ERROR_OFFSET, for example:

#define OTL_EXCEPTION_ENABLE_ERROR_OFFSET
#define OTL_EXCEPTION_STM_TEXT_SIZE 32767

OTL_EXTENDED
_EXCEPTION
 
(for enabling the otl_exception's extended fields for OTL/ODBC and OTL/DB2-CLI). This is for fixing problem 47.
OTL_ODBC_
ALTERNATE_
RPC

This #define should be used with the PostgreSQL ODBC driver. The driver returns as many row counts via SQLRowCount() calls as there are rows in a batch INSERT statement. The #define enables a loop that fetches all individual row counts and sums them up (+=). As a result, otl_stream::get_rpc() returns the total, which is correct for PostgreSQL. Normally, commercially available ODBC drivers return a single row count on a batch INSERT.
OTL_ODBC_
LOGOFF_
FREES_
HANDLES
Some ODBC drivers can't reuse underlying ODBC connect related resources. In order for OTL to fully recover from a database failure, the resources need to be released and new resources need to be allocated for otl_connect objects to work. Some versions of the Oracle ODBC driver for Oracle show that type behavior. This #define forces otl_connect::logoff() to the ODBC connect resources so that the next call to otl_connect::rlogon() would allocate the resources again.
OTL_ODBC_
STRING_TO_
TIMESTAMP

This #define defines conversion from the string/varchar format to the timestamp format (otl_datetime), for example, PostgreSQL's timestamps with time zone, or MS SQL Server 2008's datetimeoffset(7):

for PostgreSQL:
#define OTL_ODBC_STRING_TO_TIMESTAMP(str,tm)            \
{ \
sscanf(str, \
"%04d-%02d-%02d %02d:%02d:%02d.%06ld%hd", \
&tm.year, \
&tm.month, \
&tm.day, \
&tm.hour, \
&tm.minute, \
&tm.second, \
&tm.fraction, \
&tm.tz_hour); \
}

for PostgreSQL and #define OTL_UNICODE:

#define OTL_ODBC_STRING_TO_TIMESTAMP(str,tm)            \
{ \
swscanf(str, \
L"%04d-%02d-%02d %02d:%02d:%02d.%06ld%hd", \
&tm.year, \
&tm.month, \
&tm.day, \
&tm.hour, \
&tm.minute, \
&tm.second, \
&tm.fraction, \
&tm.tz_hour); \
}


for MS SQL 2008:
#define OTL_ODBC_STRING_TO_TIMESTAMP(str,tm)              \
{ \
sscanf(str, \
"%04d-%02d-%02d %02d:%02d:%02d.%07ld %hd:%hd", \
&tm.year, \
&tm.month, \
&tm.day, \
&tm.hour, \
&tm.minute, \
&tm.second, \
&tm.fraction, \
&tm.tz_hour, \
&tm.tz_minute); \
}

for MS SQL 2008 and #define OTL_UNICODE

#define OTL_ODBC_STRING_TO_TIMESTAMP(str,tm)              \
{                                                         \
  swscanf(str,                                            \
           L"%04d-%02d-%02d %02d:%02d:%02d.%07ld %hd:%hd",\
           &tm.year,                                      \
           &tm.month,                                     \
           &tm.day,                                       \
           &tm.hour,                                      \
           &tm.minute,                                    \
           &tm.second,                                    \
           &tm.fraction,                                  \
           &tm.tz_hour,                                   \
           &tm.tz_minute);                                \
}
OTL_ODBC_
SQL_STATEMENT_
WITH_DIAG_REC_
OUTPUT
Some MS SQL Server commands (like BACKUP, DBCC, etc.) don't use result sets to communicate their output. They use diagnostic record format instead. Microsoft recommends to use SQLExecDirect() instead of SQLPrepare + SQLExecute with such commands. Also, such commands take time to execute. However, some of the commands return control back from the SQLExecDirect() call right away. For example, BACKUP does that. For the BACKUP to successfully finish, it requires for the statement handle to be valid. Therefore the OTL direct exec functions can't be used. In order to work around this limitation, the otl_stream class was extended to execute MS SQL Server's BACKUP, DBCC, etc., commands. This #define is needed for the otl_stream class to recognize these commands. This #define specifies a function that accepts an SQL statement text, and returns true, in one of the commands is recognized, for example:

inline bool sql_statement_with_diag_rec_output(const char* stm_text)
{
  if(strncmp(stm_text,"BACKUP",6)==0)
    return true;
  else if(strncmp(stm_text,"DBCC",4)==0)
    return true;
  else
    return false;
}

#define OTL_ODBC_SQL_STATEMENT_WITH_DIAG_REC_OUTPUT \
        sql_statement_with_diag_rec_output

Also, see otl_stream:::get_next_diag_rec() function, and examples 688, 689.
OTL_ODBC_
TIMESTAMP_
TO_STRING

This #define defines conversion the timestamp format (otl_datetime) to the string/varchar format, for example, PostgreSQL's timestamp with time zone, or MS SQL Server 2008's datetimeoffset(7):

for PostgreSQL:
#define OTL_ODBC_TIMESTAMP_TO_STRING(tm,str)            \
{ \
sprintf(str, \
"%04d-%02d-%02d %02d:%02d:%02d.%06ld %+hd", \
tm.year, \
tm.month, \
tm.day, \
tm.hour, \
tm.minute, \
tm.second, \
tm.fraction, \
tm.tz_hour); \
}


for PostgreSQL and #define OTL_UNICODE:
#define OTL_ODBC_TIMESTAMP_TO_STRING(tm,str)             \
{ \
swprintf(str, \
L"%04d-%02d-%02d %02d:%02d:%02d.%06ld %+hd", \
tm.year, \
tm.month, \
tm.day, \
tm.hour, \
tm.minute, \
tm.second, \
tm.fraction, \
tm.tz_hour); \
}

for MS SQL 2008:
#define OTL_ODBC_TIMESTAMP_TO_STRING(tm,str)                    \
{ \
sprintf(str, \
"%04d-%02d-%02d %02d:%02d:%02d.%07ld %+hd:%hd", \
tm.year, \
tm.month, \
tm.day, \
tm.hour, \
tm.minute, \
tm.second, \
tm.fraction, \
tm.tz_hour, \
tm.tz_minute); \
}


for MS SQL 2008 and #define OTL_UNICODE:

#define OTL_ODBC_TIMESTAMP_TO_STRING(tm,str)                    \
{ \
swprintf(str, \
L"%04d-%02d-%02d %02d:%02d:%02d.%07ld %+hd:%hd", \
tm.year, \
tm.month, \
tm.day, \
tm.hour, \
tm.minute, \
tm.second, \
tm.fraction, \
tm.tz_hour, \
tm.tz_minute); \
}
OTL_ODBC_
TIME_ZONE
This #define enables tz_hour, and tz_minute fields in the otl_datetime class. ODBC doesn't support the time zone components yet, so this #define needs to be used with #define OTL_ODBC_STRING_TO_TIMESTAMP and #define OTL_ODBC_TIMESTAMP_TO_STRING.
OTL_FREETDS_
ODBC_
WORKAROUNDS
FreeTDS/ODBC doesn't seem to implement the database session's "auto-commit off" mode, so otl_connect's auto_commit  has no effect. In order to work around this deficiency, this #define should be used. When the #define is enabled, OTL executes "begin transaction" statement before each transaction. otl_connect::commit() or otl_connect::rollback() can be used to commit or roll back the transaction. When FreeTDS/ODBC implements the database session's "auto-commit off" mode, the #define could be safely removed, because the otl_connect's auto-commit parameter would take effect on the database sessions. For the time being, this #define is recommended for use with FreeTDS/ODBC against MS SQL. otl_connect::auto_commit_on() / otl_connect::auto_commit_off() functions don't work for MS SQL with FreeTDS/ODBC. Until a fix becomes available, it's not recommended to use them.

Sybase is slightly different: otl_connect::auto_commit_on() / otl_connect::auto_commit_off() functions seem to work even though the otl_connect::rlogon()'s auto_commit doesn't work. After rlogon() has been called, it's recommended to call auto_commit_off(). See Sybase SQL Server / FreeTDS ODBC examples for more detail.

In FreeTDS/ODBC, the default for the database session's auto-commit mode is "auto-commit ON", which can't be turned off or on again. When #define OTL_FREETDS_ODBC_WORKAROUNDS is enabled, OTL emulates the database session's "auto-commit off" mode by executing "begin transaction" at the beginning of each transaction, and not executing anything when the "auto-commit" is set to ON, which is the default in FreeTDS/ODBC.
 
Also, FreeTDS/ODBC doesn't support "transaction isolation" level, that is, otl_connect::set_transaction_isolation_level() has no effect. Until the feature is implemented in FreeTDS/ODBC, it's recommended that explicit server side settings should be used instead. For example, MS SQL supports an explicit (NOLOCK) option on the FROM clause in a SELECT statement. Sybase has the "set transaction isolation level X" command to set an explicit, session-wide transaction isolation level.

OTL_MAP_
SQL_GUID_
TO_CHAR

Before OTL 4.0.140, MS SQL GUIDs (uniqueidentifier) were mapped to char[XXX]. OTL 4.0.140 and higher  maps the GUIDs to raw[16], This #define should be used to map GUIDs to char[XXX] by default. Of course, the new default mapping can be overridden manually Also, see example 105.
OTL_MAP_
SQL_BINARY_
TO_CHAR

Before OTL 4.0.140, MS SQL TIMESTAMPs were mapped to char[XXX], which was effectively a conversion from the binary format to the hexadecimal string format. OTL 4.0.140 and higher maps MS SQL TIMESTAMPs to raw[XXX]. This #define should be used to map MS SQL TIMESTAMPs to  the hexadecimal string format by default. Of course, the new default mapping can be overridden manually. 
OTL_MAP_
SQL_VARBINARY_
TO_RAW_LONG

Before OTL 4.0.140,, "binary" database types were mapped to raw_long. OTL 4.0.140 and higher maps the "binary" types to raw[XXX]  This #define should be used to map the binary types to raw_long by default. Of course, the new default mapping can be overridden manually.  Also, see example 346.
OTL_STREAM_
LEGACY_
BUFFER_
SIZE_TYPE

OTL 4.0.115 introduces a larger data type for the OTL stream buffer size: int instead of the old short int. The buffer size parameter was short int for a long time to keep all OTL based code compatible with older database APIs (like original OCI7, or restrictions on some old ODBC drivers), and portable across platforms / databases. Now is time to move on. "int" as a datatype for the buffer size provides a much wider value range. "int" is the default for the OTL stream buffer size parameter from OTL 4.0.115 and on. However, those old, legacy applications based on OTL cannot be left behind. This #define, when enabled, turns the old "short int" type for the buffer size back on.
OTL_FUNC
_THROW_SPEC_ON
 
This #define works in a combination with #define OTL_ANSI_CPP (when OTL_ANSI_CPP is defined). This #define enables the function throw specification clause (introduced in OTL 4.0.50) in all OTL functions, to make them explicitly declare what type C++ exceptions the function may throw. It looks like there is no consesus in the C++ community whether function throw specs are good or not, and I decided to make it up to each OTL user to whether enable or not enable this OTL feature  by introducing this #define.
OTL_ORA_
LEGACY_
NUMERIC_TYPES

This #define should be used in a combination with #define OTL_ORA10G, or OTL_ORA10G_R2, or OTL_ORA11G. It disables the use of OCI10 native SQLT_BDOUBLE / SQLT_BFLOAT bindings, and reverts to SQLT_FLT bindings, which are compatible with older versions of the OCI. This define can be enabled when the Oracle Client 10g, or 11g is used against older versions of the Oracle server, say, Oracle 9.2. When the OCI10 native SQLT_BDOUBLE / SQLT_BFLOAT bindings are used via the Oracle 10 Client with, say, Oracle 9i database back end, the bindings don't work, because the Oracle 9i server doesn't support them.
OTL_ORA_
MAP_BIGINT_
TO_LONG
This #define enables the mapping from <bigint> for 64-bit OCIs for LP64 platforms to signed 64-bit longs. It's a more efficient alternative to the char[XXX] binding and bigint-string / string-bigint conversion (see also the following #define's: OTL_BIGINTOTL_BIGINT_TO_STR,   OTL_STR_TO_BIGINT).
OTL_MAP_
LONG_TO_
SQL_C_SBIGINT

In the ODBC/DB2 CLI standard, SQL_C_SLONG contains 32 bits regardless of the size of "long int" on a given 64-bit platform. Similarly, SQL_C_SBIGINT is a signed 64-bit integer, regardless of whether the platform is 32-bit or 64-bit. ODBC drivers have different implementations of SQL_C_SLONG, meaning that some ODBC drivers deviate from the standard. OTL tries to cover all implementations of the SQL_C_SLONG. This #define maps "long" (in bind variable declarations) into SQL_C_SBIGINT in case if sizeof(long) == 8. For example, :v1<long> will be mapped to SQL_C_SBIGINT, which is a signed 64-bit integer.
OTL_NO_TMPL_
MEMBER_
FUNC_
SUPPORT

OTL 4.0.127 or higher tries to use template member functions for implementing operator >>/<< for numeric data types (int, unsigned, short, long, float, double, signed 64-bit int) for C++ compilers that have support for the feature.  However, even after so many years since the C++ standard was adopted back in the summer of 1998, some C++ compilers either still have bugs in their support of the feature, or are missing any support completely. If that happens, it's possible to make OTL fall back on the old proven plain nontemplate member functions. This #define can be used to do just that.
OTL_ORA_
SUBSCRIBE

This #define enables the otl_subscriber class. The class is Oracle 9/10 (or higher) specific. It uses the Oracle Change Notification OCI functions, which allow the user to get notified about changes on database tables of interest. This feature is especially useful in an Oracle RAC environment, though the interface works in a stand alone Oracle instance. When #define OTL_ORA_SUBSCRIBE is enabled, the following #define's need to enabled as well:
#define OTL_ORA_OCI_ENV_CREATE
#define OTL_ORA_OCI_ENV_CREATE_MODE (OCI_THREADED|OCI_OBJECT|OCI_EVENTS)
OTL_ORA_UTF8
This #define enables OCI9i/10g support for Oracle UTF8 character encodings (UTF8, AL32UTF8). This #define is mutually exclusive with #define OTL_UNICODE, which supports UTF-16. UTF-8 seems to be more popular with Oracle C++ developers at least in Linux/Unix. The basic difference between UTF-8 and UTF-16 is that UTF-8 is byte oriented. It's okay to use a '\0' terminated array of unsigned chars with UTF-8 as opposed to an array of unsigned 16-bit integers with UTF-16.
OTL_ORA7_
STRING_TO_
TIMESTAMP
OCI7 is still important even when used against Oracle 9i or Oracle 10g. In fact, OCI7 is supported by all Oracle Clients with no exception, and it is called the classic OCI. In addition to DATE, Oracle 9i introduced TIMESTAMP as a new temporal data type which supports fractional parts of the second: milliseconds, microseconds, etc. Sometimes, there is a need to use TIMESTAMPs and OCI7 together in order to enhance legacy applications. This #define makes the use of TIMESTAMPs transparaent through OCI7. For example:

#define OTL_ORA7 // Compile OTL 4.0/OCI7
#define OTL_ORA7_TIMESTAMP_TO_STRING(tm,s)      \
{                                               \
  sprintf(s,                                    \
          "%02d/%02d/%04d %02d:%02d:%02d.%06ld",\
          tm.month,                             \
          tm.day,                               \
          tm.year,                              \
          tm.hour,                              \
          tm.minute,                            \
          tm.second,                            \
          tm.fraction                           \
         );                                     \
}

#define OTL_ORA7_STRING_TO_TIMESTAMP(s,tm)       \
{                                                \
  sscanf(s,                                      \
          "%02d/%02d/%04d %02d:%02d:%02d.%06ld", \
          &tm.month,                             \
          &tm.day,                               \
          &tm.year,                              \
          &tm.hour,                              \
          &tm.minute,                            \
          &tm.second,                            \
          &tm.fraction                           \
         );                                      \
}

#define
OTL_ORA7_STRING_TO_TIMESTAMP and #define OTL_ORA7_TIMESTAMP_TO_STRING should be used together as shown in the example above. These #defines define string-to-timestamp and timestamp-to-string conversion so that operator<</>>(otl_datetime&) can be used transparently with :var<char[XXX]> bind variables. Also, see example 473.

Oracle 10g seems to have a bug that when #define OTL_ORA_TIMESTAMP is enabled, it takes much more time than usual to retrieve timestamp values from a table. The same bug was reported with the Oracle 10g JDBC driver, so it may be a deficiency in the Oracle network protocol. #define OTL_ORA7_TIMESTAMP_TO_STRING and #define OTL_ORA7_STRING_TO_TIMESTAMP are supported for OTL/ORA8,8i,9i,10g,11g, and can be used as a workaround for the Oracle network protocol deficiency. Under #define OTL_UNICODE,
the following OTL_ORA7_STRING_TO_TIMESTAMP/OTL_ORA7_TIMESTAMP_TO_STRING can be used:

#define OTL_ORA7_TIMESTAMP_TO_STRING(tm,s)       \
{                                                \
  swprintf(s,                                    \
          L"%02d/%02d/%04d %02d:%02d:%02d.%06ld",\
          tm.month,                              \
          tm.day,                                \
          tm.year,                               \
          tm.hour,                               \
          tm.minute,                             \
          tm.second,                             \
          tm.fraction                            \
         );                                      \
}

#define OTL_ORA7_STRING_TO_TIMESTAMP(s,tm)        \
{                                                 \
  swscanf(s,                                      \
          L"%02d/%02d/%04d %02d:%02d:%02d.%06ld", \
          &tm.month,                              \
          &tm.day,                                \
          &tm.year,                               \
          &tm.hour,                               \
          &tm.minute,                             \
          &tm.second,                             \
          &tm.fraction                            \
         );                                       \
}



OTL_ORA7_
TIMESTAMP_TO_
STRING
This #define should be used together with #define OTL_ORA7_STRING_TO_TIMESTAMP.
OTL_ORA_
MAP_STRINGS_
TO_CHARZ
OTL normally binds a variable size string buffer (host variable) with both VARCHAR() and CHAR() columns. ODBC and DB2 CLI handle variable size vs padded string comparison semantic correctly for both types of string columns. OCIx do that a little bit differently. So, when OTL/OCIx is used with CHAR() columns, if, say, a WHERE clause has a char[XXX] bind variable, the actual strings for the WHERE clause need to be padded to the full length of the CHAR() columns. #define OTL_ORA_MAP_STRINGS_TO_CHARZ changes the OTL default binding of string host variables. When the #define is enabled, OTL makes "CHARZ" type string bindings, which behaves exactly the same as ODBC / DB2 CLI. However, this type of string binding has a slightly higher runtime overhead. It's up to the database developer to make the right decision on balancing out performance vs protability / readability of the source code.
OTL_ORA_
MAX_UNICODE_
VARCHAR_
SIZE
When OTL_UNICODE, OTL_ORA8I / OTL_ORA9I are enabled, and the stream is instantiated with a SELECT statement that has two (or more) large VARCHAR2(4000), or NVARCHAR2(2000), Oracle may generate the following error: ORA-01461 (Invalid length...). The error has to do with the fact that Oracle (8i/9i) treats large VARCHAR2s / NVARCHAR2s as LONGs, which means that there may be only one large VARCHAR2 / NVARCHAR2 in a SELECT statement. The only workaround that Oracle Corporation recommends for Oracle 8i/9i is that the size of  large VARCHAR2s/NVARCHAR2s on a SELECT statement needs to be limited to 4000 bytes. For PL/SQL block that have large VARCHAR2/NVARCHAR2 the workaround doesn't apply, that is, there is no such error, simply because PL/SQL treats large strings differently. #define OTL_ORA_MAX_UNICODE_VARCHAR_SIZE implements the workaround:

#define OTL_UNICODE
#define OTL_ORA8I
//#define OTL_ORA9I
int my_max_unicode_varchar_string_size=32000;
  // in bytes, the number is not precise,
  // the actual maximum may be higher
#define OTL_ORA_MAX_UNICODE_VARCHAR_SIZE (
my_max_unicode_varchar_string_size)
#include <otlv4.h>
...
  my_max_unicode_varchar_string_size=32000; // in bytes
  otl_stream o(...); // PL/SQL block that has large VARCHAR/NVARCHAR strings
...
  my_max_unicode_varchar_string_size=4000; // in bytes
  otl_stream s(...); // SELECT statement that has two or more large VARCHAR2/NVARCHAR2 strings
  my_max_unicode_varchar_string_size=32000; // in bytes
...

All of the above is NOT needed under #define OTL_ORA10G / OTL_ORA10G_R2, or when there is no more than one large VARCHAR2/NVARCHAR2 in the same SELECT. Sorry for this complicated stuff: a compliacted bug requires a kludgy fix. The workaround is not needed for Oracle 10g because Oracle 10g changed the architecture, compared with Oracle 9i in how large Unicode VARCHAR2 / NVARCHAR2 are handled inside the Oracle Client / Server.



OTL_ORA_
OCI_ENV_
CREATE

This #define can only be used when one of the following is defined: OTL_ORA8I, OTL_ORA9I, OTL_ORA10G, OTL_ORA10G_R2. The #define enables OCI Environment Handle initialization via OCIEnvCreate() instead of the older OCIInitialize() + OCIEnvInit() scheme. I don't want to go too deep into the discussion of what works, and what doesn't work. Those who want to use OCIEnvCreate(), be my guests.


OTL_ORA_
OCI_ENV_
CREATE_
MODE

This define should be used in a combination with #define OTL_ORA_OCI_ENV_CREATE. When OTL_ORA_OCI_ENV_CREATE_MODE is defined, it overrides the mode (OCI_DEFAULT/OCI_THREADED) in which OCI environment handles will be created. For example:

#define OTL_ORA_OCI_ENV_CREATE
#define OTL_ORA_OCI_ENV_CREATE_MODE OCI_THREADED

The problem that this #define is trying to address is that the "default/threaded" mode was passed into otl_connect::otl_initialize() once in the whole program, instead of having to pass the same parameter into all calls to otl_connect::rlogon() or server_attach(). When this #define is enabled, it overrides everything else, so that the custom code wouldn't have to be changed.
OTL_STREAM_
NO_PRIVATE_
BOOL_
OPERATORS

By default, OTL makes otl_stream::operator>>(bool&) and operator<<(const bool) private because they are not implemented, and in some cases it is very confusing when the C++ compiler use a different operator, say, instead of operator>>(bool&) . It makes it harder to track down bugs in the code at runtime.  By making the operators private,  the runtime bugs of that sort become more obvious at compile time. However, there may be legitimate use cases when there is a need to overload operator>>(bool&) and operator<<(const bool). This #define, when enabled, prevents OTL from declaring private operator>>(bool&) and operator<<(const bool) in the otl_stream class.
OTL_STREAM_
NO_PRIVATE_
UNSIGNED_
LONG_
OPERATORS

By default, OTL makes otl_stream::operator>>(unsigned long&) and operator<<(const unsigned long) private because they are not implemented, and in some cases it is very confusing when the C++ compiler use a different operator, say, instead of operator>>(unsigned long&). It makes it harder to track down bugs in the code at runtime.  By making the operators private,  the runtime bugs of that sort become more obvious at compile time. However, there may be legitimate use cases when there is a need to overload operator>>(unsigned long&) and operator<<(const unsigned long). This #define, when enabled, prevents OTL from declaring private operator>>(unsigned long&) and operator<<(const unsigned long) in the otl_stream class.
OTL_STRICT_
NUMERIC_TYPE_
CHECK_
ON_SELECT
By default on an SELECT statement, or a stored procedure that returns an implcit result set (ODBC, DB2 CLI) / a reference cursor (PL/SQL), OTL tries to describe the [SELECT] output columns, and map internal datatypes to external C++ datatypes.  In the case of internal numeric datatypes, the corresponding external C++ datatypes may not have exactly the same domain as the internal datatypes. And, say, the values are being read into a variable of a third numeric datatype. In this case OTL has to convert the values from one numeric datatype to another. This #define (OTL_STRICT_NUMERIC_TYPE_CHECK_ON_SELECT) enforces the exact match between the output variable's datatype that's the internal numeric value is being read into, and the datatype of the internal value itself.

In some cases, as it was mentioned in the previous paragraph, the internal-to-external numeric datatype mapping is not exact. In those case, the numeric [SELECT] column's datatype may be explicitly overriden to ensure the exact match between the internal and the external datatypes. Also, if the external and internal datatypes match exactly, OTL provides a small performance boost by avoiding any numeric datatype conversion.
OTL_ODBC_SQL
_EXTENDED
_FETCH_ON

(for ODBC and DB2-CLI). Forces OTL to generate calls to SQLExtendedFetch (buffer size > 1), or SQLFetch (buffer size ==1), instead of SQLFetchScroll, in case if the ODBC level is greater of equal to ODBC 3.0. This #define is introduced to mainly fix a bug in DB2-CLI in Linux, and some ODBC drivers, when CLOBs/BLOBs are being fetched with SQLFetchScroll().
OTL_ODBC_
SELECT_STM_
EXECUTE_
BEFORE_
DESCRIBE
This #define (#define OTL_ODBC_SELECT_STM_EXECUTE_BEFORE_DESCRIBE) should be used in a combination with #define OTL_ODBC, and it changes the OTL stream's default sequence of ODBC functions in the case of SELECT statement. The default from sequence is as follows: SQLPrepare(), SQLDescribeCol(),..., SQLBindParameter(),..., SQLExecute(), SQLFetch(). New ODBC drivers tend to do more optmization of database round-trips, and they return the SELECT column descriptions along with the first batch of rows. The ODBC specifation calls this kind of optimization an implementaion detail, and leaves it up to the implometors of ODBC driver. In the case of such optimization, the sequence of ODBC function becomes this: SQPrepare(), SQLBindParameter(),..., SQLExecute(), SQLDescribeCol(), ..., SQLFetch().
OTL_ORA_
DECLARE_
COMMON_
READ_
STREAM_
INTERFACE
(for OCI8/8i/9i/10g only). Whe this #define is enabled, OTL declares the following abstract / interface class which both otl_refcur_stream and otl_stream get derived from:

class otl_read_stream_interface{
public:
 
  virtual int is_null(void) = 0;
  virtual void rewind(void) = 0;
  virtual int eof(void) = 0;
  virtual otl_read_stream_interface& operator>>(otl_datetime& s) = 0;
  virtual otl_read_stream_interface& operator>>(char& c) = 0;
  virtual otl_read_stream_interface& operator>>(unsigned char& c) = 0;
  virtual otl_read_stream_interface& operator>>(OTL_STRING_CONTAINER& s) = 0;
  virtual otl_read_stream_interface& operator>>(char* s) = 0;
  virtual otl_read_stream_interface& operator>>(unsigned char* s) = 0;
  virtual otl_read_stream_interface& operator>>(int& n) = 0;
  virtual otl_read_stream_interface& operator>>(unsigned& u) = 0;
  virtual otl_read_stream_interface& operator>>(short& sh) = 0;
  virtual otl_read_stream_interface& operator>>(long int& l) = 0;
  virtual otl_read_stream_interface& operator>>(float& f) = 0;
  virtual otl_read_stream_interface& operator>>(double& d) = 0;
  virtual otl_read_stream_interface& operator>>(otl_long_string& s) = 0;
  virtual otl_read_stream_interface& operator>>(otl_lob_stream& s) = 0;
  virtual otl_column_desc* describe_select(int& desc_len) = 0;

  virtual otl_var_desc* describe_out_vars(int& desc_len);
    virtual otl_var_desc* describe_next_out_var(void);

   virtual ~otl_read_stream_interface(){}

};

This interface is useful when there is a lot of common code for fetching rows either via otrl_stream or via otl_refcur_stream.

OTL_ORA_
DOES_NOT_
UNDEF_
MIN_MAX
OTL/OCI8/8i/9i/10g #undef's #define min and #define max that are defined in one of the OCI header files. This was done because in some cases min() and max() were declared as functions in C++ standard header files. However, when ATL is used, min() and max() are defined as #define's in "windef.h". If the OTL header file is included after the windef.h file, the min() and max() #defines get #undef''ined by OTL, so the symbols become unavailable. When #define OTL_ORA_DOES_NOT_UNDEF_MIN_MAX) is enabled, it makes OTL keep #define min and #define max as they were defined (if they were defined).
OTL_ORA
_TEXT_ON
.
When fstream.h gets included before the OTL header file, fstream.h declares object "text", which is part of the C++ stream environment. Oracle OCI header files use symbol "text" as well. Depending on the platform and the C++ compiler, symbol "text" is defined in OCI either as a typedef or a #define. In any case, it interferes with the C++ "text", defined in fstream.h. #define OTL_ORA_TEXT_ON is introduced to fix the problem. So, all the user needs to do in order to make fstream.h and the OTL header compile together is to put #define OTL_ORA_TEXT_ON before including the OTL header file, and after #include <fstream.h>. In the case of fstream.h being include after the OTL header file, #define OTL_ORA_TEXT_ON also needs to be defined before the inclusion of the OTL header file.
OTL_ORA
_TIMESTAMP
This #define enables support for Oracle 9i's timestamps, timestamps with time zones, and timestamps with local time zones. The #define forces OTL to use the OCI "OCIDateTime*" resource instead of the OCI 7-byte date structure. OCIDateTime allows the timestamp values (down to microseconds and time zone hours/minutes) to be written and read. OCI 8.1.7 has support for OCIDateTime's when they are used with Oracle 9i on the back end, meaning that Oracle Client 8.1.7 can be connected to Oracle 9i, and OTL_ORA_TIMESTAMP can be enabled at the same time. In other words, #define OTL_ORA8I, or #define OTL_ORA9I can be used  in a combination with OTL_ORA_TIMESTAMP, if the underlynig Oracle Client (OCI) libraries have the corresponding functionality.

PL/SQL (index-by) tables of otl_datetime's, that are bound with "tables of timestamps" are not supported this time around, due to some bugs in the OCI code (I just could not track down the problem: no info on metalink.oracle.com, no references on dejanews either, no code samples). TIMESTAMPs, as parametrs in stored procedures, can be used with otl_datetime's. PL/SQL (index-by) table can be boud with "tables of DATEs", as usual.
OTL_STR_
_TO_BIGINT(str,n)
This #define is required when OTL_BIGINT is enabled and when one of OTL_ORAxx #defines is enabled, in order to support OTL internal string-to-bigint conversion. This #define is supposed to provide string-to-bigint conversion code that is most probably C++ compiler specific (because 64-bit ints are not part of the ANSI C++ standard), for example:

#if defined(__GNUC__) // GNU C++

#include <stdlib.h>

#define OTL_BIGINT long long

#define OTL_STR_TO_BIGINT(str,n) \
{ \
n=strtoll(str,0,10); \
}

#define OTL_BIGINT_TO_STR(n,str) \
{ \
sprintf(str,"%lld",n); \
}


#endif

OTL_STREAM_
READ_
ITERATOR_ON
This #define enables the  OTL stream read iterator, which provides a JDBC-like getter interface.
Typically, OTL stream read iterators can be used with SELECT statements, stored prcoredures that return implicit result sets (ODBC, DB2-CLI), or stored procedures that return referenced cursors (Oracle).
OTL_THROWS_
ON_SQL_SUCCESS_
WITH_INFO

OTL/ODBC, OTL/DB2-CLI only. This #define enables the following function: otl_connect::set_throw_on_sql_success_with_info().  When the function sets the "throw flag", OTL  throws an otl_exceptioin if SQLExecute() / SQLExecDirect() returns SQL_SUCCESS_WITH_INFO. By raising an exception on SQL_SUCCESS_WITH_INFO, OTL makes it possible to communicate messages that would normally get retrieved via SQLGetDiagRec() calls right after SQLExecute() / SQLExecDirect() returns. In order to get the maximum amount of diagnostic information from the ODBC driver, this #define should be used in a combination with #define OTL_EXTENDED_EXCEPTION.
OTL_TRACE_LEVEL

OTL_TRACE_
STREAM

OTL_TRACE
_LINE_PREFIX

OTL_TRACE_
LINE_SUFFIX

OTL_TRACE_ENABLE_
STREAM_LABELS
These #defines enable OTL function call tracing. OTL tracing uses the C++ stream interface (ostream, fstream) to log OTL function calls with arguments, "this" addresses of class instances, etc.
  • #define OTL_TRACE_LEVEL specifies a level of OTL tracing. Each type of tracing is represented by its own bit in the whole trace level unsigned  int value:

    1. 0x1 -- traces the following functions of the otl_connect class (1st level of tracing): rlogon(), logoff(), commit(), rollback(), auto_commit_on(), auto_commit_off()
    2. 0x2 -- traces otl_cursor::direct_exec(), direct execution of static SQL statements, no otl_streams (2nd level of tracing).
    3. 0x4 -- traces the following functions of the otl_stream class: open(), close()
    4. 0x8 -- traces internal "execute SQL statement" function, internal "fetch the first bacth of rows" function, internal "fetch the next batch of rows" function (3rd level of tracing).
    5. 0x10 -- traces the operator >> and << functions of the otl_stream class (4th level of tracing)
    6. 0x20 -- traces all otl_exception's raised by OTL.


  • #define OTL_TRACE_STREAM specifies a log stream variable, or a function call that returns a file stream reference. What is defined by this #define is used as an output file stream variable inside OTL.

  • #define OTL_TRACE_LINE_PREFIX can be used to override the default OTL trace line prefix: "OTL TRACE ==>". If it is more convenient to have something different from the default, say, for running a Perl script on an OTL log file to mine for patterns.

  • #define OTL_TRACE_LINE_SUFFIX can be used to override the default OTL trace line suffix: "\n". If it is more convenient to have something different from the default, say, for running a Perl script on an OTL log file to mine for patterns.

  • #define OTL_TRACE_ENABLE_STREAM_LABELS can be used to enable logging of otl_stream labels instead of SQL statement bodies. See The Oracle, DB2-CLI, and ODBC specific otl_stream descriptions for more detail.
#define OTL_TRACE_LEVEL may be either a constant, or a variable, or a function call that returns the trace level dynamically. If OTL_TRACE_LEVEL is not defined then tracing calls are not generated, and therefore there is not any runtime performance penalty. Even if #define OTL_TRACE_LEVEL is defined, performance degradation is very small, if the level of tracing is set relatively low.

Example:
      unsigned int my_trace_level=
0x1 | // 1st level of tracing
0x2 | // 2nd level of tracing
0x4 | // 3rd level of tracing
0x8 | // 4th level of tracing
0x10| // 5th level of tracing
0x20; // 6th level of tracing
// each level of tracing is represented by its own bit,
// so levels of tracing can be combined in an arbitrary order.

#define OTL_TRACE_LEVEL my_trace_level
// enables OTL tracing, and use my_trace_level
// as a trace control variable.

#define OTL_TRACE_STREAM cerr
// directs all OTL tracing to cerr

#define OTL_TRACE_LINE_PREFIX "MY OTL TRACE ==> "
// redefines the default OTL trace line prefix.
// This #define is optional

#define OTL_TRACE_LINE_SUFFIX std::endl
// redefines the default OTL trace line suffix.
// This #define is optional

Also,  see OTL examples for more detail.
OTL_STL  (for turning on std::strings, and STL-compliant OTL stream iterators: otl_input_iterator, otl_output_iterator)
OTL_STL_NOSTD
_NAMESPACE
 
(for excluding namespace std, when #define OTL_STL is on). This is mainly for fixing problem 42.
OTL_STLPORT (the same as #define OTL_STL, only for use with STLPort 4.x). This #define makes OTL compile with STLPort 4.x.
OTL_STREAM
_POOLING_ON
 
(for enabling otl_stream pooling). This #define requires #define OTL_STL to be defined first because STL containers were used in the implementation of the otl_stream pooling. For more detail, see examples 113, 114, 115.
OTL_UNCAUGHT
_EXCEPTION_ON
 
(for enabling a safer exception handling and error recovery). This is for fixing problem 46.

From OTL 4.0.162 and on, the #define becomes the default in order to address user complaints. The rationale for making it the default at this point in time is that thr C++ compilers support the stardard C++ uncaught_exception() function more or less. OTL 4.0.167 and higher do not enable this #define by default for Visual C++ 6.0.
OTL_UNICODE_
STRING_TYPE_
CAST_FROM_
CHAR
When #define OTL_UNICODE, #define OTL_ORA8I/9I/10G/10G_R2, and #define OTL_UNICODE_STRING_TYPE are enabled, a string class that is different from std::wstring may be used, for example:

#define OTL_ORA10G
#defined OTL_UNICODE
...
#define OTL_UNICODE_STRING_TYPE my_wide_char_string

Let's also assume that my_wide_char_string is not 100% compatible with std::wstring and doesn't have the following function

     assign(const charT* s, size_type n)

In order for OTL to handle wide character strings of my_wide_char_string type, it needs to know how to efficiently make a string out of a raw buffer + the string length. #define OTL_UNICODE_STRING_TYPE_CAST_FROM_CHAR can be used for passing into the OTL layer a piece of code that does the conversion. For example, say, ACE_TString is used:

#define OTL_ORA10G_R2
#defined OTL_UNICODE
#define OTL_UNICODE_CHAR_TYPE wchar_t
#define OTL_UNICODE_STRING_TYPE ACE_TString
#define OTL_UNICODE_STRING_TYPE_CAST_FROM_CHAR(s, c_ptr, len) {s.set(c_ptr,len,1);}

OTL_USER_DEFINED
_STRING_CLASS_ON
(for defining a string class, other than STL's std::string, for reading from/writing to the otl_stream). This #define goes in pair with #define USER_DEFINED_STRING_CLASS, which is used to define the actual string class name.Fore more detail, see examples 119, 120, 121
OTL_USER_
DEFINED_STRING_
CLASS_DEFAULT_
NULL_TO_VAL
This #define OTL_USER_DEFINED_STRING_CLASS_DEFAULT_NULL_TO_VAL(s) can be used in the case if a C++ string class is used with OTL in order to read string values tothe database., and to default string NULLs to a predefined value. If string NULLs need to be defaulted to an empty string, some C++ string classes have more efficient ways than assigning an empty string to an actual string variable. Especially, when the variable is used a reusable buffer.

For example, ACE_TString has fast_clear(), which keeps the string internal buffer. It just assigns '\0' to the first element of the internal buffer, and sets the length indicator to 0. Here's what the #define should look like in the case of ACE_TString and the desired default value for string NULLs is an empty string:

#define OTL_USER_DEFINED_STRING_CLASS_DEFAULT_NULL_TO_VAL(s) {s.fast_clear();}

std::string can be cleared via std::string::clear(), for example:

#define OTL_USER_DEFINED_STRING_CLASS_DEFAULT_NULL_TO_VAL(s) { s.clear();}

This feature becomes more important if your OTL based C++ code starts relying of defaulting string NULLs to a value, especially in a multi-threaded environment, and an  inefficient dynamic heap manager.
OTL_UNICODE
This #define enables Unicode string support in OTL for Oracle8i (UCS-2), and for Oracle 9i/10g (UTF-16). Character string lengths change from byte semantic to character semantic, meaning that sizes are given in characters rather than in bytes. For more detail, refer to the corresponding Oracle manuals on nationalization / globalization. For example, in Oracle 8i, if a string column is, say, VARCHAR2(60), 60 is the size of the column in bytes. In Oracle 9i, the size will be characters. In Oracle 10g, it maybe specified in bytes or characters. The OTL manual is not a substitute for the Oracle manuals.

Starting with version 4.0.108, OTL supports Unicode strings for OTL/ODBC, and OTL/DB2-CLI. Unicode string data can be accessed in Oracle via ODBC, MS SQL via ODBC, and DB2 via DB2-CLI/ODBC.
OTL_UNICODE_
CHAR_TYPE

This #define is used in a combinatiuon with OTL_UNICODE. The #define specifies a compiler specific, 2-byte Unicode character type.:

#define OTL_UNICODE
#define OTL_UNICODE_CHAR_TYPE wchar_t

When your C++ compiler doesn't have any appropriate Unicode compatible character type, unsigned short can be used instead:

#define OTL_UNICODE
#define OTL_UNICODE_CHAR_TYPE unsigned short


OTL_UNICODE_
EXCEPTION_AND_
RLOGON

This #define enables support for Unicode otl_exception's msg, sqlstate data members, and an otl_connect::rlogon() function that accepts Unicode user id, password, and DSN. This #define should be enabled only when #define UNICODE / _UNICODE is enabled for ODBC / DB2 CLI, In other words, when Unicode ODBC driver functions are enabled. Also, it's recommened that this #define be used in a conbination with OTL_UNICODE, and OTL_UNICODE_CHAR_TYPE, for example:

#define OTL_UNICODE
#define OTL_UNICODE_CHAR_TYPE wchar_t
#define OTL_UNICODE_EXCEPTION_AND_RLOGON

OTL_UNICODE_
STRING_TYPE

This #define enables std::wstring as 2-byte Unicode strings in OTL. It can be used when wstring is based on a wchar_t that corresponds to 2-byte Unicode:

#define OTL_UNICODE
#define OTL_UNICODE_CHAR_TYPE wchar_t
#define OTL_UNICODE_STRING_TYPE wstring

If your C++ compiler doesn't have std::wstring class defined (say, only std::string is defined), it is possible to instantiate std::basic_string<XXX>, where XXX is your 2-byte Unicode type, for example, your 2-byte Unicode is unsigned short:

#include <string>
namespace std{
    typedef unsigned short my_unicode_char;
    typedef basic_string<my_unicode_type> my_unicode_string;
}
#define OTL_UNICODE
#define OTL_UNICODE_CHAR_TYPE my_unicode_char
#define OTL_UNICODE_STRING_TYPE my_unicode_string

More specifically, GNU C++ doesn't implement std::wstring, so the example above should be useful for GNU C++ at least.

OTL_UNICODE_
USE_ANSI_
ODBC_FUNCS_
FOR_DATA_DICT
This #define should be used as a workaround for an MS SQL Server ODBC driver bug. It's not possible to say for sure what the scope of the bug (or may be it's a an undocumented feature!) is. OTL provides access to the data dictionary ODBC / DB2 CLI functions. When Unicode ODBC function prototypes are enabled via #define UNICODE / _UNICODE, the corresponding Unicode ODBC data dictionary functions are enabled. However, some of the Unicode ODBC data dictionary functions don't work correctly when the MS SQL Server Unicode ODBC driver is used. As a workaround, ANSI ODBC data dictionary functions can be used instead, even if the output string bind variables are Unicode. #define OTL_UNICODE_USE_ANSI_ODBC_FUNCS_FOR_DATA_DICT makes OTL generate ANSI ODBC data dictionary function calls instead of the Unicode ODBC data dictionary function calls.

OTL_VALUE
_TEMPLATE_ON
 
(for enabling otl_value<T>). The otl_value<T> template class can be also enabled with #define OTL_STL. #define OTL_VALUE_TEMPLATE_ON allows the template class to be enabled without turning on STL compliance. Not all C++ compilers compile OTL under #define OTL_STL. #define OTL_VALUE_TEMPLATE_ON was introduced In order to relax that limitation. Fore more detail, see examples 119, 120, 121
OTL_VERSION
_NUMBER

This #define holds the version number of the OTL header file, in which the #define is defined. For example, OTL 4.0.17 is defined as (0x040011L). This #define allows the user to keep track of OTL version numbers, e.g. the #define makes it possible to do more complex conditional compilation.
OTL_UNCAUGHT_
EXCEPTION_OWN_
NAMESPACE

When OTL is used with STL Port (#define OTL_STLPORT), STL Port library may be configured not to expose some std:: functions like uncaught_exception() in its namespace _STL. In order to work around the problem, #define OTL OTL_UNCAUGHT_EXCEPTION_OWN_NAMESPACE is introduced:

#define OTL_UNCAUGHT_EXCEPTION_OWN_NAMESPACE __std_alias::
...
#include <otlv4.h>

This #define tells OTL what namespace to prefix the uncaught_exception() function with. In OTL 4.0.167 or higher, this #define is obsolete, and has no effect.
 

The macro definitions may be defined directly in the program's code, or turned on via C++ compiler command line
option, e.g.: -DOTL_ODBC, -DOTL_ORA7, -DOTL_ORA8, -DOTL_ORA8I, -DOTL_ORA9I,, -DOTL_ODBC_UNIX, -DOTL_ODBC_MYSQL, -DOTL_DB2_CLI, -DOTL_ODBC_TIMESTEN_WIN, -DOTL_ODBC_TIMESTEN_UNIX

In order to compile and link OTL with an underlying database API, the following header files and libraries of the database API are needed (<ORACLE_HOME>,  <DB2_HOME>,  <TimesTen_HOME>, and <INFORMIX_HOME> are home directories for installations of Oracle, DB2, TimesTen, and Informix):

API
API header files for  Windows
API libraries for Windows
OCI7
In <ORACLE_HOME>\oci\include
 <ORACLE_HOME>\oci\lib\<compiler_specific>\ociw32.lib
OCI8
In <ORACLE_HOME>\oci\include  <ORACLE_HOME>\oci\lib\<compiler_specific>\oci.lib
OCI8i
In <ORACLE_HOME>\oci\include  <ORACLE_HOME>\oci\lib\<compiler_specific>\oci.lib
OCI9i
In <ORACLE_HOME>\oci\include  <ORACLE_HOME>\oci\lib\<compiler_specific>\oci.lib
OCI10g
In <ORACLE_HOME>\oci\include  <ORACLE_HOME>\oci\lib\<compiler_specific>\oci.lib
ODBC
Normally, in one of the C++ compiler system directories, no need to include explicitly.
Normally, in one of the C++ compiler system directories: odbc32.lib
DB2 CLI
In <DB2_HOME>\include
<DB2_HOME>\lib\db2api.lib
<DB2_HOME>\lib\db2cli.lib
TimesTen  ODBC
• Directly with the TimesTen ODBC driver

      in <TimesTen_HOME>\include


• Directly with the TimesTen Client ODBC driver

      in <TimesTen_HOME>\include

• With an ODBC driver manager (to be used with #define OTL_ODBC, no TimeSten ODBC extensions are available)

       normally, in one of the C++ compiler system directories, no need to include explicitly.

• Directly with the TimesTen ODBC driver

      <TimesTen_HOME>\lib\TTEN70.LIB
      <TimesTen_HOME>\lib\TTDV70.LIB

• Directly with the TimesTen Client ODBC driver

    <TimesTen_HOME>\lib\TTCL70.LIB

• With an ODBC driver manager

      normally, in one of the C++ compiler system directories: odbc32.lib
Informix CLI
Default ODBC header files for the C++ compiler.
odbc32.lib


API
API header files for Unix
API libraries for Unix
OCI7
-I$(ORACLE_HOME)/rdbms/demo  -I$(ORACLE_HOME)/rdbms/public
-L$(ORACLE_HOME)/lib/ -lclntsh
OCI8
-I$(ORACLE_HOME)/rdbms/demo  -I$(ORACLE_HOME)/rdbms/public -L$(ORACLE_HOME)/lib/ -lclntsh
OCI8i
-I$(ORACLE_HOME)/rdbms/demo  -I$(ORACLE_HOME)/rdbms/public -L$(ORACLE_HOME)/lib/ -lclntsh
OCI9i
-I$(ORACLE_HOME)/rdbms/demo  -I$(ORACLE_HOME)/rdbms/public -L$(ORACLE_HOME)/lib/ -lclntsh
OCI10g
-I$(ORACLE_HOME)/rdbms/demo  -I$(ORACLE_HOME)/rdbms/public -L$(ORACLE_HOME)/lib/ -lclntsh
ODBC
ODBC bridge specific. If you're using unixodbc, see its manuals for more detail.
ODBC bridge specific. If you're using unixodbc, see its manuals for more detail
DB2 CLI
-I/<DB2_HOME>/sqllib/include
-L/<DB2_HOME>/sqllib/lib -ldb2
TimesTen ODBC
-I<TimesTen_HOME>/include
To link with the TimesTen Data Manager ODBC Driver

    -L <TimesTen_HOME>/lib -ltten

To link with the TimesTen Client ODBC Driver:

    -L<TimesTen_HOME>/lib -lttclient
Informix CLI
-I<INFORMIX_HOME>/incl/cli
-L<INFORMIX_HOME>/lib -lifdmr -lthcli


For more detail, see the manul of your C++ compiler and the database API manuals.


Prev NextContentsGo Home

Copyright © 1996, 2009, Sergei Kuchin, email: skuchin@aceweb.com, skuchin@gmail.com  

Permission to use, copy, modify and redistribute this document for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies.