OdbcConnection.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /* -*- C++ -*- */
  2. /****************************************************************************
  3. ** Copyright (c) 2001-2014
  4. **
  5. ** This file is part of the QuickFIX FIX Engine
  6. **
  7. ** This file may be distributed under the terms of the quickfixengine.org
  8. ** license as defined by quickfixengine.org and appearing in the file
  9. ** LICENSE included in the packaging of this file.
  10. **
  11. ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
  12. ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  13. **
  14. ** See http://www.quickfixengine.org/LICENSE for licensing information.
  15. **
  16. ** Contact ask@quickfixengine.org if any conditions of this licensing are
  17. ** not clear to you.
  18. **
  19. ****************************************************************************/
  20. #ifndef HAVE_ODBC
  21. #error OdbcConnection.h included, but HAVE_ODBC not defined
  22. #endif
  23. #ifdef HAVE_ODBC
  24. #ifndef FIX_ODBCCONNECTION_H
  25. #define FIX_ODBCCONNECTION_H
  26. #ifdef _MSC_VER
  27. #pragma warning( disable : 4503 4355 4786 4290 )
  28. #pragma comment( lib, "Odbc32" )
  29. #endif
  30. #include "Utility.h"
  31. #include <sql.h>
  32. #include <sqlext.h>
  33. #include <sqltypes.h>
  34. #include <sstream>
  35. #include "DatabaseConnectionID.h"
  36. #include "DatabaseConnectionPool.h"
  37. #include "Exceptions.h"
  38. #include "Mutex.h"
  39. namespace FIX
  40. {
  41. inline std::string odbcError( SQLSMALLINT statementType, SQLHANDLE handle )
  42. {
  43. SQLCHAR state[6];
  44. SQLINTEGER error;
  45. SQLCHAR text[SQL_MAX_MESSAGE_LENGTH];
  46. SQLSMALLINT textLength;
  47. RETCODE result = SQLGetDiagRec
  48. ( statementType, handle, 1, state, &error, text, sizeof(text), &textLength );
  49. if( result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO )
  50. return std::string( (char*)text );
  51. return "";
  52. }
  53. inline bool odbcSuccess( RETCODE result )
  54. {
  55. return result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO;
  56. }
  57. class OdbcQuery
  58. {
  59. public:
  60. OdbcQuery( const std::string& query )
  61. : m_statement( 0 ), m_result( 0 ), m_query( query )
  62. {}
  63. ~OdbcQuery()
  64. {
  65. close();
  66. }
  67. void close()
  68. {
  69. if( m_statement )
  70. {
  71. SQLFreeHandle( SQL_HANDLE_STMT, m_statement );
  72. m_statement = 0;
  73. m_result = 0;
  74. }
  75. }
  76. bool execute( HDBC connection )
  77. {
  78. if( m_statement ) SQLFreeHandle( SQL_HANDLE_STMT, m_statement );
  79. SQLAllocHandle( SQL_HANDLE_STMT, connection, &m_statement );
  80. m_result = SQLExecDirect( m_statement, (SQLCHAR*)m_query.c_str(), m_query.size() );
  81. if( success() || m_result == SQL_NO_DATA )
  82. return true;
  83. m_reason = odbcError( SQL_HANDLE_STMT, m_statement );
  84. SQLFreeHandle( SQL_HANDLE_STMT, m_statement );
  85. m_statement = 0;
  86. return success();
  87. }
  88. bool success()
  89. {
  90. return odbcSuccess( m_result );
  91. }
  92. /*int rows()
  93. {
  94. return (int)mysql_num_rows( m_result );
  95. }*/
  96. const std::string& reason()
  97. {
  98. return m_reason;
  99. }
  100. bool fetch()
  101. {
  102. return odbcSuccess( SQLFetch(m_statement) );
  103. }
  104. /*char* getValue( int row, int column )
  105. {
  106. if( m_rows.empty() )
  107. {
  108. MYSQL_ROW row = 0;
  109. while( row = mysql_fetch_row( m_result ) )
  110. m_rows.push_back(row);
  111. }
  112. return m_rows[row][column];
  113. }*/
  114. HSTMT statement()
  115. {
  116. return m_statement;
  117. }
  118. void throwException() throw( IOException )
  119. {
  120. if( !success() )
  121. throw IOException( "Query failed [" + m_query + "] " + reason() );
  122. }
  123. private:
  124. HSTMT m_statement;
  125. RETCODE m_result;
  126. std::string m_query;
  127. std::string m_reason;
  128. };
  129. class OdbcConnection
  130. {
  131. public:
  132. OdbcConnection
  133. ( const DatabaseConnectionID& id )
  134. : m_connection( 0 ), m_environment( 0 ), m_connectionID( id )
  135. {
  136. connect();
  137. }
  138. OdbcConnection
  139. ( const std::string& user, const std::string& password,
  140. const std::string& connectionString )
  141. : m_connection( 0 ), m_environment( 0 ), m_connectionID( "", user, password, connectionString, 0 )
  142. {
  143. connect();
  144. }
  145. ~OdbcConnection()
  146. {
  147. if( m_connection )
  148. {
  149. SQLDisconnect( m_connection );
  150. SQLFreeHandle( SQL_HANDLE_DBC, m_connection );
  151. SQLFreeHandle( SQL_HANDLE_ENV, m_environment );
  152. }
  153. }
  154. const DatabaseConnectionID& connectionID()
  155. {
  156. return m_connectionID;
  157. }
  158. bool connected()
  159. {
  160. Locker locker( m_mutex );
  161. return m_connected;
  162. }
  163. bool reconnect()
  164. {
  165. Locker locker( m_mutex );
  166. SQLDisconnect( m_connection );
  167. SQLFreeHandle( SQL_HANDLE_DBC, m_connection );
  168. m_connection = 0;
  169. connect();
  170. return true;
  171. }
  172. bool execute( OdbcQuery& pQuery )
  173. {
  174. Locker locker( m_mutex );
  175. if( !pQuery.execute( m_connection ) )
  176. {
  177. reconnect();
  178. return pQuery.execute( m_connection );
  179. }
  180. return true;
  181. }
  182. private:
  183. void connect()
  184. {
  185. m_connected = false;
  186. RETCODE result;
  187. if(!m_environment)
  188. {
  189. result = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_environment );
  190. if( !odbcSuccess(result) )
  191. throw ConfigError( "Unable to allocate ODBC environment" );
  192. result = SQLSetEnvAttr(m_environment, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
  193. if( !odbcSuccess(result) )
  194. throw ConfigError( "Unable to find ODBC version 3.0" );
  195. }
  196. result = SQLAllocHandle( SQL_HANDLE_DBC, m_environment, &m_connection );
  197. if( !odbcSuccess(result) )
  198. throw ConfigError( "Unable to allocate ODBC connection" );
  199. std::stringstream connectionStream;
  200. std::string connectionString = m_connectionID.getHost();
  201. if( m_connectionID.getHost().find("UID=") == std::string::npos )
  202. connectionStream << "UID=" << m_connectionID.getUser() << ";";
  203. if( m_connectionID.getHost().find("PWD=") == std::string::npos )
  204. connectionStream << "PWD=" << m_connectionID.getPassword() << ";";
  205. connectionStream << m_connectionID.getHost();
  206. connectionString = connectionStream.str();
  207. SQLCHAR connectionStringOut[255];
  208. result = SQLDriverConnect(
  209. m_connection, NULL,
  210. (SQLCHAR*)connectionString.c_str(), SQL_NTS,
  211. connectionStringOut, 255,
  212. 0, SQL_DRIVER_NOPROMPT );
  213. if( !odbcSuccess(result) )
  214. {
  215. std::string error = odbcError( SQL_HANDLE_DBC, m_connection );
  216. throw ConfigError( error );
  217. }
  218. m_connected = true;
  219. }
  220. HENV m_environment;
  221. HDBC m_connection;
  222. bool m_connected;
  223. DatabaseConnectionID m_connectionID;
  224. Mutex m_mutex;
  225. };
  226. }
  227. #endif
  228. #endif