00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef HAVE_ODBC
00023 #error OdbcConnection.h included, but HAVE_ODBC not defined
00024 #endif
00025
00026 #ifdef HAVE_ODBC
00027 #ifndef FIX_ODBCCONNECTION_H
00028 #define FIX_ODBCCONNECTION_H
00029
00030 #ifdef _MSC_VER
00031 #pragma warning( disable : 4503 4355 4786 4290 )
00032 #pragma comment( lib, "Odbc32" )
00033 #endif
00034
00035 #include "Utility.h"
00036 #include <sql.h>
00037 #include <sqlext.h>
00038 #include <sqltypes.h>
00039 #include <sstream>
00040 #include "DatabaseConnectionID.h"
00041 #include "DatabaseConnectionPool.h"
00042 #include "Exceptions.h"
00043 #include "Mutex.h"
00044
00045 namespace FIX
00046 {
00047
00048 inline std::string odbcError( SQLSMALLINT statementType, SQLHANDLE handle )
00049 {
00050 SQLCHAR state[6];
00051 SQLINTEGER error;
00052 SQLCHAR text[SQL_MAX_MESSAGE_LENGTH];
00053 SQLSMALLINT textLength;
00054 RETCODE result = SQLGetDiagRec
00055 ( statementType, handle, 1, state, &error, text, sizeof(text), &textLength );
00056 if( result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO )
00057 return std::string( (char*)text );
00058 return "";
00059 }
00060
00061 inline bool odbcSuccess( RETCODE result )
00062 {
00063 return result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO;
00064 }
00065
00066 class OdbcQuery
00067 {
00068 public:
00069 OdbcQuery( const std::string& query )
00070 : m_statement( 0 ), m_result( 0 ), m_query( query )
00071 {}
00072
00073 ~OdbcQuery()
00074 {
00075 close();
00076 }
00077
00078 void close()
00079 {
00080 if( m_statement )
00081 {
00082 SQLFreeHandle( SQL_HANDLE_STMT, m_statement );
00083 m_statement = 0;
00084 m_result = 0;
00085 }
00086 }
00087
00088 bool execute( HDBC connection )
00089 {
00090 if( m_statement ) SQLFreeHandle( SQL_HANDLE_STMT, m_statement );
00091 SQLAllocHandle( SQL_HANDLE_STMT, connection, &m_statement );
00092 m_result = SQLExecDirect( m_statement, (SQLCHAR*)m_query.c_str(), m_query.size() );
00093 if( success() || m_result == SQL_NO_DATA )
00094 return true;
00095 m_reason = odbcError( SQL_HANDLE_STMT, m_statement );
00096 SQLFreeHandle( SQL_HANDLE_STMT, m_statement );
00097 m_statement = 0;
00098 return success();
00099 }
00100
00101 bool success()
00102 {
00103 return odbcSuccess( m_result );
00104 }
00105
00106
00107
00108
00109
00110
00111 const std::string& reason()
00112 {
00113 return m_reason;
00114 }
00115
00116 bool fetch()
00117 {
00118 return odbcSuccess( SQLFetch(m_statement) );
00119 }
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132 HSTMT statement()
00133 {
00134 return m_statement;
00135 }
00136
00137 void throwException() throw( IOException )
00138 {
00139 if( !success() )
00140 throw IOException( "Query failed [" + m_query + "] " + reason() );
00141 }
00142
00143 private:
00144 HSTMT m_statement;
00145 RETCODE m_result;
00146 std::string m_query;
00147 std::string m_reason;
00148 };
00149
00150 class OdbcConnection
00151 {
00152 public:
00153 OdbcConnection
00154 ( const DatabaseConnectionID& id )
00155 : m_connection( 0 ), m_environment( 0 ), m_connectionID( id )
00156 {
00157 connect();
00158 }
00159
00160 OdbcConnection
00161 ( const std::string& user, const std::string& password,
00162 const std::string& connectionString )
00163 : m_connection( 0 ), m_environment( 0 ), m_connectionID( "", user, password, connectionString, 0 )
00164 {
00165 connect();
00166 }
00167
00168 ~OdbcConnection()
00169 {
00170 if( m_connection )
00171 {
00172 SQLDisconnect( m_connection );
00173 SQLFreeHandle( SQL_HANDLE_DBC, m_connection );
00174 SQLFreeHandle( SQL_HANDLE_ENV, m_environment );
00175 }
00176 }
00177
00178 const DatabaseConnectionID& connectionID()
00179 {
00180 return m_connectionID;
00181 }
00182
00183 bool connected()
00184 {
00185 Locker locker( m_mutex );
00186 return m_connected;
00187 }
00188
00189 bool reconnect()
00190 {
00191 Locker locker( m_mutex );
00192 SQLDisconnect( m_connection );
00193 SQLFreeHandle( SQL_HANDLE_DBC, m_connection );
00194 m_connection = 0;
00195 connect();
00196 return true;
00197 }
00198
00199 bool execute( OdbcQuery& pQuery )
00200 {
00201 Locker locker( m_mutex );
00202 if( !pQuery.execute( m_connection ) )
00203 {
00204 reconnect();
00205 return pQuery.execute( m_connection );
00206 }
00207 return true;
00208 }
00209
00210 private:
00211 void connect()
00212 {
00213 m_connected = false;
00214
00215 RETCODE result;
00216 if(!m_environment)
00217 {
00218 result = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_environment );
00219 if( !odbcSuccess(result) )
00220 throw ConfigError( "Unable to allocate ODBC environment" );
00221
00222 result = SQLSetEnvAttr(m_environment, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
00223 if( !odbcSuccess(result) )
00224 throw ConfigError( "Unable to find ODBC version 3.0" );
00225 }
00226
00227 result = SQLAllocHandle( SQL_HANDLE_DBC, m_environment, &m_connection );
00228 if( !odbcSuccess(result) )
00229 throw ConfigError( "Unable to allocate ODBC connection" );
00230
00231 std::stringstream connectionStream;
00232 std::string connectionString = m_connectionID.getHost();
00233 if( m_connectionID.getHost().find("UID=") == std::string::npos )
00234 connectionStream << "UID=" << m_connectionID.getUser() << ";";
00235 if( m_connectionID.getHost().find("PWD=") == std::string::npos )
00236 connectionStream << "PWD=" << m_connectionID.getPassword() << ";";
00237 connectionStream << m_connectionID.getHost();
00238 connectionString = connectionStream.str();
00239
00240 SQLCHAR connectionStringOut[255];
00241
00242 result = SQLDriverConnect(
00243 m_connection, NULL,
00244 (SQLCHAR*)connectionString.c_str(), SQL_NTS,
00245 connectionStringOut, 255,
00246 0, SQL_DRIVER_NOPROMPT );
00247
00248 if( !odbcSuccess(result) )
00249 {
00250 std::string error = odbcError( SQL_HANDLE_DBC, m_connection );
00251 throw ConfigError( error );
00252 }
00253
00254 m_connected = true;
00255 }
00256
00257 HENV m_environment;
00258 HDBC m_connection;
00259 bool m_connected;
00260 DatabaseConnectionID m_connectionID;
00261 Mutex m_mutex;
00262 };
00263 }
00264
00265 #endif
00266 #endif