OdbcConnection.h
Go to the documentation of this file.
00001 /* -*- C++ -*- */
00002 
00003 /****************************************************************************
00004 ** Copyright (c) 2001-2014
00005 **
00006 ** This file is part of the QuickFIX FIX Engine
00007 **
00008 ** This file may be distributed under the terms of the quickfixengine.org
00009 ** license as defined by quickfixengine.org and appearing in the file
00010 ** LICENSE included in the packaging of this file.
00011 **
00012 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00013 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00014 **
00015 ** See http://www.quickfixengine.org/LICENSE for licensing information.
00016 **
00017 ** Contact ask@quickfixengine.org if any conditions of this licensing are
00018 ** not clear to you.
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   /*int rows()
00107   {
00108     return (int)mysql_num_rows( m_result );
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   /*char* getValue( int row, int column )
00122   {
00123     if( m_rows.empty() )
00124     {
00125       MYSQL_ROW row = 0;
00126       while( row = mysql_fetch_row( m_result ) )
00127         m_rows.push_back(row);
00128     }
00129     return m_rows[row][column];
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

Generated on Mon Sep 15 2014 01:23:54 for QuickFIX by doxygen 1.7.6.1 written by Dimitri van Heesch, © 1997-2001