OdbcStore.cpp
Go to the documentation of this file.
00001 /****************************************************************************
00002 ** Copyright (c) 2001-2014
00003 **
00004 ** This file is part of the QuickFIX FIX Engine
00005 **
00006 ** This file may be distributed under the terms of the quickfixengine.org
00007 ** license as defined by quickfixengine.org and appearing in the file
00008 ** LICENSE included in the packaging of this file.
00009 **
00010 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00011 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00012 **
00013 ** See http://www.quickfixengine.org/LICENSE for licensing information.
00014 **
00015 ** Contact ask@quickfixengine.org if any conditions of this licensing are
00016 ** not clear to you.
00017 **
00018 ****************************************************************************/
00019 
00020 #ifdef _MSC_VER
00021 #include "stdafx.h"
00022 #else
00023 #include "config.h"
00024 #endif
00025 
00026 #ifdef HAVE_ODBC
00027 
00028 #ifndef SQLLEN
00029 #define SQLLEN SQLINTEGER
00030 #endif
00031 
00032 #include "OdbcStore.h"
00033 #include "SessionID.h"
00034 #include "SessionSettings.h"
00035 #include "FieldConvertors.h"
00036 #include "Parser.h"
00037 #include "Utility.h"
00038 #include "strptime.h"
00039 #include <fstream>
00040 
00041 namespace FIX
00042 {
00043 
00044 const std::string OdbcStoreFactory::DEFAULT_USER = "sa";
00045 const std::string OdbcStoreFactory::DEFAULT_PASSWORD = "";
00046 const std::string OdbcStoreFactory::DEFAULT_CONNECTION_STRING 
00047   = "DATABASE=quickfix;DRIVER={SQL Server};SERVER=(local);";
00048 
00049 OdbcStore::OdbcStore
00050 ( const SessionID& s, const std::string& user, const std::string& password, 
00051   const std::string& connectionString )
00052   : m_sessionID( s )
00053 {
00054   m_pConnection = new OdbcConnection( user, password, connectionString );
00055   populateCache();
00056 }
00057 
00058 OdbcStore::~OdbcStore()
00059 {
00060   delete m_pConnection;
00061 }
00062 
00063 void OdbcStore::populateCache()
00064 {
00065   std::stringstream queryString;
00066 
00067   queryString << "SELECT creation_time, incoming_seqnum, outgoing_seqnum FROM sessions WHERE "
00068   << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00069   << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00070   << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00071   << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "'";
00072 
00073   OdbcQuery query( queryString.str() );
00074 
00075   if( !m_pConnection->execute(query) )
00076     throw ConfigError( "Unable to connect to database" );
00077   
00078   int rows = 0;
00079   while( query.fetch() )
00080   {
00081     rows++;
00082     if( rows > 1 )
00083       throw ConfigError( "Multiple entries found for session in database" );
00084 
00085     SQL_TIMESTAMP_STRUCT creationTime;  
00086     SQLLEN creationTimeLength;
00087     SQLGetData( query.statement(), 1, SQL_C_TYPE_TIMESTAMP, &creationTime, 0, &creationTimeLength );
00088     SQLLEN incomingSeqNum;
00089     SQLLEN incomingSeqNumLength;
00090     SQLGetData( query.statement(), 2, SQL_C_SLONG, &incomingSeqNum, 0, &incomingSeqNumLength );
00091 
00092     SQLLEN outgoingSeqNum;
00093     SQLLEN outgoingSeqNumLength;
00094     SQLGetData( query.statement(), 3, SQL_C_SLONG, &outgoingSeqNum, 0, &outgoingSeqNumLength );
00095 
00096     UtcTimeStamp time;
00097     time.setYMD( creationTime.year, creationTime.month, creationTime.day );
00098     time.setHMS( creationTime.hour, creationTime.minute, creationTime.second, creationTime.fraction );
00099     m_cache.setCreationTime( time );
00100     m_cache.setNextTargetMsgSeqNum( incomingSeqNum );
00101     m_cache.setNextSenderMsgSeqNum( outgoingSeqNum );
00102   }
00103   query.close();
00104 
00105   if( rows == 0 )
00106   {
00107     UtcTimeStamp time = m_cache.getCreationTime();
00108     char sqlTime[ 20 ];
00109     int year, month, day, hour, minute, second, millis;
00110     time.getYMD (year, month, day);
00111     time.getHMS (hour, minute, second, millis);
00112     STRING_SPRINTF (sqlTime, "%d-%02d-%02d %02d:%02d:%02d",
00113              year, month, day, hour, minute, second);
00114     std::stringstream queryString2;
00115     queryString2 << "INSERT INTO sessions (beginstring, sendercompid, targetcompid, session_qualifier,"
00116     << "creation_time, incoming_seqnum, outgoing_seqnum) VALUES("
00117     << "'" << m_sessionID.getBeginString().getValue() << "',"
00118     << "'" << m_sessionID.getSenderCompID().getValue() << "',"
00119     << "'" << m_sessionID.getTargetCompID().getValue() << "',"
00120     << "'" << m_sessionID.getSessionQualifier() << "',"
00121     << "{ts '" << sqlTime << "'},"
00122     << m_cache.getNextTargetMsgSeqNum() << ","
00123     << m_cache.getNextSenderMsgSeqNum() << ")";
00124 
00125     OdbcQuery query2( queryString2.str() );
00126     if( !m_pConnection->execute(query2) )
00127       throw ConfigError( "Unable to create session in database" );
00128   }
00129 }
00130 
00131 MessageStore* OdbcStoreFactory::create( const SessionID& s )
00132 {
00133   if( m_useSettings )
00134     return create( s, m_settings.get(s) );
00135   else if( m_useDictionary )
00136     return create( s, m_dictionary );
00137   else
00138     return new OdbcStore( s, m_user, m_password, m_connectionString );
00139 }
00140 
00141 void OdbcStoreFactory::destroy( MessageStore* pStore )
00142 {
00143   delete pStore;
00144 }
00145 
00146 MessageStore* OdbcStoreFactory::create( const SessionID& s, const Dictionary& settings )
00147 {
00148   std::string user = DEFAULT_USER;
00149   std::string password = DEFAULT_PASSWORD;
00150   std::string connectionString = DEFAULT_CONNECTION_STRING;
00151 
00152   try { user = settings.getString( ODBC_STORE_USER ); }
00153   catch( ConfigError& ) {}
00154 
00155   try { password = settings.getString( ODBC_STORE_PASSWORD ); }
00156   catch( ConfigError& ) {}
00157 
00158   try { connectionString = settings.getString( ODBC_STORE_CONNECTION_STRING ); }
00159   catch( ConfigError& ) {}
00160 
00161   return new OdbcStore( s, user, password, connectionString );
00162 }
00163 
00164 bool OdbcStore::set( int msgSeqNum, const std::string& msg )
00165 throw ( IOException )
00166 {
00167   std::string msgCopy = msg;
00168   string_replace( "'", "''", msgCopy );
00169 
00170   std::stringstream queryString;
00171   queryString << "INSERT INTO messages "
00172   << "(beginstring, sendercompid, targetcompid, session_qualifier, msgseqnum, message) "
00173   << "VALUES ("
00174   << "'" << m_sessionID.getBeginString().getValue() << "',"
00175   << "'" << m_sessionID.getSenderCompID().getValue() << "',"
00176   << "'" << m_sessionID.getTargetCompID().getValue() << "',"
00177   << "'" << m_sessionID.getSessionQualifier() << "',"
00178   << msgSeqNum << ","
00179   << "'" << msgCopy << "')";
00180 
00181   OdbcQuery query( queryString.str() );
00182   if( !m_pConnection->execute(query) )
00183   {
00184     query.close();
00185     std::stringstream queryString2;
00186     queryString2 << "UPDATE messages SET message='" << msgCopy << "' WHERE "
00187     << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00188     << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00189     << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00190     << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "' and "
00191     << "msgseqnum=" << msgSeqNum;
00192     OdbcQuery query2( queryString2.str() );
00193     if( !m_pConnection->execute(query2) )
00194       query2.throwException();
00195   }
00196   return true;
00197 }
00198 
00199 void OdbcStore::get( int begin, int end,
00200                     std::vector < std::string > & result ) const
00201 throw ( IOException )
00202 {
00203   result.clear();
00204   std::stringstream queryString;
00205   queryString << "SELECT message FROM messages WHERE "
00206   << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00207   << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00208   << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00209   << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "' and "
00210   << "msgseqnum>=" << begin << " and " << "msgseqnum<=" << end << " "
00211   << "ORDER BY msgseqnum";
00212 
00213   OdbcQuery query( queryString.str() );
00214 
00215   if( !m_pConnection->execute(query) )
00216     query.throwException();
00217 
00218   while( query.fetch() )
00219   {
00220     std::string message;
00221     SQLVARCHAR messageBuffer[4096];
00222     SQLLEN messageLength;
00223 
00224     while( odbcSuccess(SQLGetData( query.statement(), 1, SQL_C_CHAR, &messageBuffer, 4095, &messageLength)) )
00225     {  
00226       messageBuffer[messageLength] = 0;
00227       message += (char*)messageBuffer;
00228     }
00229 
00230     result.push_back( message );
00231   }
00232 }
00233 
00234 int OdbcStore::getNextSenderMsgSeqNum() const throw ( IOException )
00235 {
00236   return m_cache.getNextSenderMsgSeqNum();
00237 }
00238 
00239 int OdbcStore::getNextTargetMsgSeqNum() const throw ( IOException )
00240 {
00241   return m_cache.getNextTargetMsgSeqNum();
00242 }
00243 
00244 void OdbcStore::setNextSenderMsgSeqNum( int value ) throw ( IOException )
00245 {
00246   std::stringstream queryString;
00247   queryString << "UPDATE sessions SET outgoing_seqnum=" << value << " WHERE "
00248   << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00249   << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00250   << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00251   << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "'";
00252   OdbcQuery query( queryString.str() );
00253   if( !m_pConnection->execute(query) )
00254     query.throwException();
00255   m_cache.setNextSenderMsgSeqNum( value );
00256 }
00257 
00258 void OdbcStore::setNextTargetMsgSeqNum( int value ) throw ( IOException )
00259 {
00260   std::stringstream queryString;
00261   queryString << "UPDATE sessions SET incoming_seqnum=" << value << " WHERE "
00262   << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00263   << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00264   << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00265   << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "'";
00266 
00267   OdbcQuery query( queryString.str() );
00268   if( !m_pConnection->execute(query) )
00269     query.throwException();
00270 
00271   m_cache.setNextTargetMsgSeqNum( value );
00272 }
00273 
00274 void OdbcStore::incrNextSenderMsgSeqNum() throw ( IOException )
00275 {
00276   m_cache.incrNextSenderMsgSeqNum();
00277   setNextSenderMsgSeqNum( m_cache.getNextSenderMsgSeqNum() );
00278 }
00279 
00280 void OdbcStore::incrNextTargetMsgSeqNum() throw ( IOException )
00281 {
00282   m_cache.incrNextTargetMsgSeqNum();
00283   setNextTargetMsgSeqNum( m_cache.getNextTargetMsgSeqNum() );
00284 }
00285 
00286 UtcTimeStamp OdbcStore::getCreationTime() const throw ( IOException )
00287 {
00288   return m_cache.getCreationTime();
00289 }
00290 
00291 void OdbcStore::reset() throw ( IOException )
00292 {
00293   std::stringstream queryString;
00294   queryString << "DELETE FROM messages WHERE "
00295   << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00296   << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00297   << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00298   << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "'";
00299 
00300   OdbcQuery query( queryString.str() );
00301   if( !m_pConnection->execute(query) )
00302     query.throwException();
00303   query.close();
00304 
00305   m_cache.reset();
00306   UtcTimeStamp time = m_cache.getCreationTime();
00307 
00308   int year, month, day, hour, minute, second, millis;
00309   time.getYMD( year, month, day );
00310   time.getHMS( hour, minute, second, millis );
00311 
00312   char sqlTime[ 20 ];
00313   STRING_SPRINTF( sqlTime, "%d-%02d-%02d %02d:%02d:%02d",
00314            year, month, day, hour, minute, second );
00315 
00316   std::stringstream queryString2;
00317   queryString2 << "UPDATE sessions SET creation_time={ts '" << sqlTime << "'}, "
00318   << "incoming_seqnum=" << m_cache.getNextTargetMsgSeqNum() << ", "
00319   << "outgoing_seqnum=" << m_cache.getNextSenderMsgSeqNum() << " WHERE "
00320   << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00321   << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00322   << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00323   << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "'";
00324 
00325   OdbcQuery query2( queryString2.str() );
00326   if( !m_pConnection->execute(query2) )
00327     query2.throwException();
00328 }
00329 
00330 void OdbcStore::refresh() throw ( IOException )
00331 {
00332   m_cache.reset();
00333   populateCache(); 
00334 }
00335 
00336 }
00337 
00338 #endif

Generated on Mon Jun 23 2014 23:49:38 for QuickFIX by doxygen 1.7.6.1 written by Dimitri van Heesch, © 1997-2001