Index Source Files Annotated Class List Alphabetical Class List Class Hierarchy Graphical Class Hierarchy

# OdbcConnection.h

Go to the documentation of this file.

    00001 /* -*- C++ -*- */
    00002
    00003 /****************************************************************************
    00004 ** Copyright (c) quickfixengine.org  All rights reserved.
    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