# 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_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_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
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_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 .

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 cmopile 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 OCI (OCI7,OCI8, OCI8i, OCI9i) supports 64-bit integers, so OTL has to emulate this 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, 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.
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 it goes out of scope. In the worst case, information about a database error may be lost.
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_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 overriden 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 overriden 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 overriden manually. Also, see example 346.
OTL_STREAM_ LEGACY_ BUFFER_ SIZE_TYPE | OTL 4.0.115 introduces a larger datatype 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 applicationz 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_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_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 exceptions, and oftentimes it is called the classic OCI. In addition to DATE, Oracle 9i introduced TIMESTAMP as a new temporal datatype 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.
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.This #define only works when #define OTL_STL is enabled.
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.

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

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>, and <DB2_HOME> are home directories for instaallations of Oracle and DB2):

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

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 | ODBC bridge specific
DB2 CLI | -I/<DB2_HOME>/sqllib/include | -L/<DB2_HOME>/sqllib/lib -ldb2

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

Prev Next Contents Go Home

Copyright © 1996, 2007, Sergei Kuchin, email: skuchin@ispwest.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.