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

Generated on Wed Apr 29 2020 19:41:30 for QuickFIX by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2001