PostgreSQLStore.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_POSTGRESQL
00027 
00028 #include "PostgreSQLStore.h"
00029 #include "SessionID.h"
00030 #include "SessionSettings.h"
00031 #include "FieldConvertors.h"
00032 #include "Parser.h"
00033 #include "Utility.h"
00034 #include "strptime.h"
00035 #include <fstream>
00036 
00037 namespace FIX
00038 {
00039 
00040 const std::string PostgreSQLStoreFactory::DEFAULT_DATABASE = "quickfix";
00041 const std::string PostgreSQLStoreFactory::DEFAULT_USER = "postgres";
00042 const std::string PostgreSQLStoreFactory::DEFAULT_PASSWORD = "";
00043 const std::string PostgreSQLStoreFactory::DEFAULT_HOST = "localhost";
00044 const short PostgreSQLStoreFactory::DEFAULT_PORT = 0;
00045 
00046 PostgreSQLStore::PostgreSQLStore
00047 ( const SessionID& s, const DatabaseConnectionID& d, PostgreSQLConnectionPool* p )
00048 : m_pConnectionPool( p ), m_sessionID( s )
00049 {
00050   m_pConnection = m_pConnectionPool->create( d );
00051   populateCache();
00052 }
00053 
00054 PostgreSQLStore::PostgreSQLStore
00055 ( const SessionID& s, const std::string& database, const std::string& user,
00056   const std::string& password, const std::string& host, short port )
00057   : m_pConnectionPool( 0 ), m_sessionID( s )
00058 {
00059   m_pConnection = new PostgreSQLConnection( database, user, password, host, port );
00060   populateCache();
00061 }
00062 
00063 PostgreSQLStore::~PostgreSQLStore()
00064 {
00065   if( m_pConnectionPool )
00066     m_pConnectionPool->destroy( m_pConnection );
00067   else
00068     delete m_pConnection;
00069 }
00070 
00071 void PostgreSQLStore::populateCache()
00072 {
00073   std::stringstream queryString;
00074 
00075   queryString << "SELECT creation_time, incoming_seqnum, outgoing_seqnum FROM sessions WHERE "
00076   << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00077   << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00078   << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00079   << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "'";
00080 
00081   PostgreSQLQuery query( queryString.str() );
00082   if( !m_pConnection->execute(query) )
00083     throw ConfigError( "No entries found for session in database" );
00084 
00085   int rows = query.rows();
00086   if( rows > 1 )
00087     throw ConfigError( "Multiple entries found for session in database" );
00088 
00089   if( rows == 1 )
00090   {
00091     struct tm time;
00092     std::string sqlTime = query.getValue( 0, 0 );
00093     strptime( sqlTime.c_str(), "%Y-%m-%d %H:%M:%S", &time );
00094     m_cache.setCreationTime (UtcTimeStamp (&time));
00095     m_cache.setNextTargetMsgSeqNum( atol( query.getValue( 0, 1 ) ) );
00096     m_cache.setNextSenderMsgSeqNum( atol( query.getValue( 0, 2 ) ) );
00097   }
00098   else
00099   {
00100     UtcTimeStamp time = m_cache.getCreationTime();
00101     char sqlTime[ 20 ];
00102     int year, month, day, hour, minute, second, millis;
00103     time.getYMD (year, month, day);
00104     time.getHMS (hour, minute, second, millis);
00105     STRING_SPRINTF( sqlTime, "%d-%02d-%02d %02d:%02d:%02d",
00106              year, month, day, hour, minute, second );
00107     std::stringstream queryString2;
00108     queryString2 << "INSERT INTO sessions (beginstring, sendercompid, targetcompid, session_qualifier,"
00109     << "creation_time, incoming_seqnum, outgoing_seqnum) VALUES("
00110     << "'" << m_sessionID.getBeginString().getValue() << "',"
00111     << "'" << m_sessionID.getSenderCompID().getValue() << "',"
00112     << "'" << m_sessionID.getTargetCompID().getValue() << "',"
00113     << "'" << m_sessionID.getSessionQualifier() << "',"
00114     << "'" << sqlTime << "',"
00115     << m_cache.getNextTargetMsgSeqNum() << ","
00116     << m_cache.getNextSenderMsgSeqNum() << ")";
00117 
00118     PostgreSQLQuery query2( queryString2.str() );
00119     if( !m_pConnection->execute(query2) )
00120       throw ConfigError( "Unable to create session in database" );
00121   }
00122 }
00123 
00124 MessageStore* PostgreSQLStoreFactory::create( const SessionID& s )
00125 {
00126   if( m_useSettings )
00127     return create( s, m_settings.get(s) );
00128   else if( m_useDictionary )
00129     return create( s, m_dictionary );
00130   else
00131   {
00132     DatabaseConnectionID id( m_database, m_user, m_password, m_host, m_port );
00133     return new PostgreSQLStore( s, id, m_connectionPoolPtr.get() );
00134   }
00135 }
00136 
00137 MessageStore* PostgreSQLStoreFactory::create( const SessionID& s, const Dictionary& settings )
00138 {
00139   std::string database = DEFAULT_DATABASE;
00140   std::string user = DEFAULT_USER;
00141   std::string password = DEFAULT_PASSWORD;
00142   std::string host = DEFAULT_HOST;
00143   short port = DEFAULT_PORT;
00144 
00145   try { database = settings.getString( POSTGRESQL_STORE_DATABASE ); }
00146   catch( ConfigError& ) {}
00147 
00148   try { user = settings.getString( POSTGRESQL_STORE_USER ); }
00149   catch( ConfigError& ) {}
00150 
00151   try { password = settings.getString( POSTGRESQL_STORE_PASSWORD ); }
00152   catch( ConfigError& ) {}
00153 
00154   try { host = settings.getString( POSTGRESQL_STORE_HOST ); }
00155   catch( ConfigError& ) {}
00156 
00157   try { port = ( short ) settings.getInt( POSTGRESQL_STORE_PORT ); }
00158   catch( ConfigError& ) {}
00159 
00160   DatabaseConnectionID id( database, user, password, host, port );
00161   return new PostgreSQLStore( s, id, m_connectionPoolPtr.get() );
00162 }
00163 
00164 void PostgreSQLStoreFactory::destroy( MessageStore* pStore )
00165 {
00166   delete pStore;
00167 }
00168 
00169 bool PostgreSQLStore::set( int msgSeqNum, const std::string& msg )
00170 throw ( IOException )
00171 {
00172   char* msgCopy = new char[ (msg.size() * 2) + 1 ];
00173   PQescapeString( msgCopy, msg.c_str(), msg.size() );
00174 
00175   std::stringstream queryString;
00176   queryString << "INSERT INTO messages "
00177   << "(beginstring, sendercompid, targetcompid, session_qualifier, msgseqnum, message) "
00178   << "VALUES ("
00179   << "'" << m_sessionID.getBeginString().getValue() << "',"
00180   << "'" << m_sessionID.getSenderCompID().getValue() << "',"
00181   << "'" << m_sessionID.getTargetCompID().getValue() << "',"
00182   << "'" << m_sessionID.getSessionQualifier() << "',"
00183   << msgSeqNum << ","
00184   << "'" << msgCopy << "')";
00185 
00186   delete [] msgCopy;
00187 
00188   PostgreSQLQuery query( queryString.str() );
00189   if( !m_pConnection->execute(query) )
00190   {
00191     std::stringstream queryString2;
00192     queryString2 << "UPDATE messages SET message='" << msg << "' WHERE "
00193     << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00194     << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00195     << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00196     << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "' and "
00197     << "msgseqnum=" << msgSeqNum;
00198     PostgreSQLQuery query2( queryString2.str() );
00199     if( !m_pConnection->execute(query2) )
00200       query2.throwException();
00201   }
00202 
00203   return true;
00204 }
00205 
00206 void PostgreSQLStore::get( int begin, int end,
00207                       std::vector < std::string > & result ) const
00208 throw ( IOException )
00209 {
00210   result.clear();
00211   std::stringstream queryString;
00212   queryString << "SELECT message FROM messages WHERE "
00213   << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00214   << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00215   << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00216   << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "' and "
00217   << "msgseqnum>=" << begin << " and " << "msgseqnum<=" << end << " "
00218   << "ORDER BY msgseqnum";
00219 
00220   PostgreSQLQuery query( queryString.str() );
00221   if( !m_pConnection->execute(query) )
00222     query.throwException();
00223 
00224   int rows = query.rows();
00225   for( int row = 0; row < rows; row++ )
00226     result.push_back( query.getValue( row, 0 ) );
00227 }
00228 
00229 int PostgreSQLStore::getNextSenderMsgSeqNum() const throw ( IOException )
00230 {
00231   return m_cache.getNextSenderMsgSeqNum();
00232 }
00233 
00234 int PostgreSQLStore::getNextTargetMsgSeqNum() const throw ( IOException )
00235 {
00236   return m_cache.getNextTargetMsgSeqNum();
00237 }
00238 
00239 void PostgreSQLStore::setNextSenderMsgSeqNum( int value ) throw ( IOException )
00240 {
00241   std::stringstream queryString;
00242   queryString << "UPDATE sessions SET outgoing_seqnum=" << value << " WHERE "
00243   << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00244   << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00245   << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00246   << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "'";
00247 
00248   PostgreSQLQuery query( queryString.str() );
00249   if( !m_pConnection->execute(query) )
00250     query.throwException();
00251 
00252   m_cache.setNextSenderMsgSeqNum( value );
00253 }
00254 
00255 void PostgreSQLStore::setNextTargetMsgSeqNum( int value ) throw ( IOException )
00256 {
00257   std::stringstream queryString;
00258   queryString << "UPDATE sessions SET incoming_seqnum=" << value << " WHERE "
00259   << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00260   << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00261   << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00262   << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "'";
00263 
00264   PostgreSQLQuery query( queryString.str() );
00265   if( !m_pConnection->execute(query) )
00266     query.throwException();
00267 
00268   m_cache.setNextTargetMsgSeqNum( value );
00269 }
00270 
00271 void PostgreSQLStore::incrNextSenderMsgSeqNum() throw ( IOException )
00272 {
00273   m_cache.incrNextSenderMsgSeqNum();
00274   setNextSenderMsgSeqNum( m_cache.getNextSenderMsgSeqNum() );
00275 }
00276 
00277 void PostgreSQLStore::incrNextTargetMsgSeqNum() throw ( IOException )
00278 {
00279   m_cache.incrNextTargetMsgSeqNum();
00280   setNextTargetMsgSeqNum( m_cache.getNextTargetMsgSeqNum() );
00281 }
00282 
00283 UtcTimeStamp PostgreSQLStore::getCreationTime() const throw ( IOException )
00284 {
00285   return m_cache.getCreationTime();
00286 }
00287 
00288 void PostgreSQLStore::reset() throw ( IOException )
00289 {
00290   std::stringstream queryString;
00291   queryString << "DELETE FROM messages WHERE "
00292   << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00293   << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00294   << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00295   << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "'";
00296 
00297   PostgreSQLQuery query( queryString.str() );
00298   if( !m_pConnection->execute(query) )
00299     query.throwException();
00300 
00301   m_cache.reset();
00302   UtcTimeStamp time = m_cache.getCreationTime();
00303 
00304   int year, month, day, hour, minute, second, millis;
00305   time.getYMD( year, month, day );
00306   time.getHMS( hour, minute, second, millis );
00307 
00308   char sqlTime[ 20 ];
00309   STRING_SPRINTF( sqlTime, "%d-%02d-%02d %02d:%02d:%02d",
00310            year, month, day, hour, minute, second );
00311 
00312   std::stringstream queryString2;
00313   queryString2 << "UPDATE sessions SET creation_time='" << sqlTime << "', "
00314   << "incoming_seqnum=" << m_cache.getNextTargetMsgSeqNum() << ", "
00315   << "outgoing_seqnum=" << m_cache.getNextSenderMsgSeqNum() << " WHERE "
00316   << "beginstring=" << "'" << m_sessionID.getBeginString().getValue() << "' and "
00317   << "sendercompid=" << "'" << m_sessionID.getSenderCompID().getValue() << "' and "
00318   << "targetcompid=" << "'" << m_sessionID.getTargetCompID().getValue() << "' and "
00319   << "session_qualifier=" << "'" << m_sessionID.getSessionQualifier() << "'";
00320 
00321   PostgreSQLQuery query2( queryString2.str() );
00322   if( !m_pConnection->execute(query2) )
00323     query2.throwException();
00324 }
00325 
00326 void PostgreSQLStore::refresh() throw ( IOException )
00327 {
00328   m_cache.reset();
00329   populateCache(); 
00330 }
00331 
00332 }
00333 
00334 #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