1 /****************************************************************************
2 ** Copyright (c) 2001-2014
3 **
4 ** This file is part of the QuickFIX FIX Engine
5 **
6 ** This file may be distributed under the terms of the quickfixengine.org
7 ** license as defined by quickfixengine.org and appearing in the file
8 ** LICENSE included in the packaging of this file.
9 **
10 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
11 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12 **
13 ** See http://www.quickfixengine.org/LICENSE for licensing information.
14 **
15 ** Contact ask@quickfixengine.org if any conditions of this licensing are
16 ** not clear to you.
17 **
18 ****************************************************************************/
19 
20 #ifdef _MSC_VER
21 #include "stdafx.h"
22 #else
23 #include "config.h"
24 #endif
25 
26 #ifdef HAVE_POSTGRESQL
27 
28 #include "PostgreSQLLog.h"
29 #include "SessionID.h"
30 #include "SessionSettings.h"
31 #include "Utility.h"
32 #include "strptime.h"
33 #include <fstream>
34 
35 namespace FIX
36 {
37 
38 const std::string PostgreSQLLogFactory::DEFAULT_DATABASE = "quickfix";
39 const std::string PostgreSQLLogFactory::DEFAULT_USER = "postgres";
40 const std::string PostgreSQLLogFactory::DEFAULT_PASSWORD = "";
41 const std::string PostgreSQLLogFactory::DEFAULT_HOST = "localhost";
42 const short PostgreSQLLogFactory::DEFAULT_PORT = 0;
43 
PostgreSQLLog(const SessionID & s,const DatabaseConnectionID & d,PostgreSQLConnectionPool * p)44 PostgreSQLLog::PostgreSQLLog
45 ( const SessionID& s, const DatabaseConnectionID& d, PostgreSQLConnectionPool* p )
46 : m_pConnectionPool( p )
47 {
48   init();
49   m_pSessionID = new SessionID( s );
50   m_pConnection = m_pConnectionPool->create( d );
51 }
52 
PostgreSQLLog(const DatabaseConnectionID & d,PostgreSQLConnectionPool * p)53 PostgreSQLLog::PostgreSQLLog
54 ( const DatabaseConnectionID& d, PostgreSQLConnectionPool* p )
55 : m_pConnectionPool( p ), m_pSessionID( 0 )
56 {
57   init();
58   m_pConnection = m_pConnectionPool->create( d );
59 }
60 
PostgreSQLLog(const SessionID & s,const std::string & database,const std::string & user,const std::string & password,const std::string & host,short port)61 PostgreSQLLog::PostgreSQLLog
62 ( const SessionID& s, const std::string& database, const std::string& user,
63   const std::string& password, const std::string& host, short port )
64   : m_pConnectionPool( 0 )
65 {
66   init();
67   m_pSessionID = new SessionID( s );
68   m_pConnection = new PostgreSQLConnection( database, user, password, host, port );
69 }
70 
PostgreSQLLog(const std::string & database,const std::string & user,const std::string & password,const std::string & host,short port)71 PostgreSQLLog::PostgreSQLLog
72 ( const std::string& database, const std::string& user,
73   const std::string& password, const std::string& host, short port )
74   : m_pConnectionPool( 0 ), m_pSessionID( 0 )
75 {
76   init();
77   m_pConnection = new PostgreSQLConnection( database, user, password, host, port );
78 }
79 
init()80 void PostgreSQLLog::init()
81 {
82   setIncomingTable( "messages_log" );
83   setOutgoingTable( "messages_log" );
84   setEventTable( "event_log" );
85 }
86 
~PostgreSQLLog()87 PostgreSQLLog::~PostgreSQLLog()
88 {
89   if( m_pConnectionPool )
90     m_pConnectionPool->destroy( m_pConnection );
91   else
92     delete m_pConnection;
93   delete m_pSessionID;
94 }
95 
create()96 Log* PostgreSQLLogFactory::create()
97 {
98   std::string database;
99   std::string user;
100   std::string password;
101   std::string host;
102   short port;
103 
104   init( m_settings.get(), database, user, password, host, port );
105   DatabaseConnectionID id( database, user, password, host, port );
106   PostgreSQLLog* result = new PostgreSQLLog( id, m_connectionPoolPtr.get() );
107   initLog( m_settings.get(), *result );
108   return result;
109 }
110 
create(const SessionID & s)111 Log* PostgreSQLLogFactory::create( const SessionID& s )
112 {
113   std::string database;
114   std::string user;
115   std::string password;
116   std::string host;
117   short port;
118 
119   Dictionary settings;
120   if( m_settings.has(s) )
121     settings = m_settings.get( s );
122 
123   init( settings, database, user, password, host, port );
124   DatabaseConnectionID id( database, user, password, host, port );
125   PostgreSQLLog* result = new PostgreSQLLog( s, id, m_connectionPoolPtr.get() );
126   initLog( settings, *result );
127   return result;
128 }
129 
init(const Dictionary & settings,std::string & database,std::string & user,std::string & password,std::string & host,short & port)130 void PostgreSQLLogFactory::init( const Dictionary& settings,
131            std::string& database,
132            std::string& user,
133            std::string& password,
134            std::string& host,
135            short &port )
136 {
137   database = DEFAULT_DATABASE;
138   user = DEFAULT_USER;
139   password = DEFAULT_PASSWORD;
140   host = DEFAULT_HOST;
141   port = DEFAULT_PORT;
142 
143   if( m_useSettings )
144   {
145     try { database = settings.getString( POSTGRESQL_LOG_DATABASE ); }
146     catch( ConfigError& ) {}
147 
148     try { user = settings.getString( POSTGRESQL_LOG_USER ); }
149     catch( ConfigError& ) {}
150 
151     try { password = settings.getString( POSTGRESQL_LOG_PASSWORD ); }
152     catch( ConfigError& ) {}
153 
154     try { host = settings.getString( POSTGRESQL_LOG_HOST ); }
155     catch( ConfigError& ) {}
156 
157     try { port = ( short ) settings.getInt( POSTGRESQL_LOG_PORT ); }
158     catch( ConfigError& ) {}
159   }
160   else
161   {
162     database = m_database;
163     user = m_user;
164     password = m_password;
165     host = m_host;
166     port = m_port;
167   }
168 }
169 
initLog(const Dictionary & settings,PostgreSQLLog & log)170 void PostgreSQLLogFactory::initLog( const Dictionary& settings, PostgreSQLLog& log )
171 {
172   try { log.setIncomingTable( settings.getString( POSTGRESQL_LOG_INCOMING_TABLE ) ); }
173   catch( ConfigError& ) {}
174 
175   try { log.setOutgoingTable( settings.getString( POSTGRESQL_LOG_OUTGOING_TABLE ) ); }
176   catch( ConfigError& ) {}
177 
178   try { log.setEventTable( settings.getString( POSTGRESQL_LOG_EVENT_TABLE ) ); }
179   catch( ConfigError& ) {}
180 }
181 
destroy(Log * pLog)182 void PostgreSQLLogFactory::destroy( Log* pLog )
183 {
184   delete pLog;
185 }
186 
clear()187 void PostgreSQLLog::clear()
188 {
189   std::stringstream whereClause;
190 
191   whereClause << "WHERE ";
192 
193   if( m_pSessionID )
194   {
195     whereClause
196     << "BeginString = '" << m_pSessionID->getBeginString().getValue() << "' "
197     << "AND SenderCompID = '" << m_pSessionID->getSenderCompID().getValue() << "' "
198     << "AND TargetCompID = '" << m_pSessionID->getTargetCompID().getValue() << "' ";
199 
200     if( m_pSessionID->getSessionQualifier().size() )
201       whereClause << "AND SessionQualifier = '" << m_pSessionID->getSessionQualifier() << "'";
202   }
203   else
204   {
205     whereClause << "BeginString = NULL AND SenderCompID = NULL && TargetCompID = NULL";
206   }
207 
208   std::stringstream incomingQuery;
209   std::stringstream outgoingQuery;
210   std::stringstream eventQuery;
211 
212   incomingQuery
213     << "DELETE FROM " << m_incomingTable << " " << whereClause.str();
214   outgoingQuery
215     << "DELETE FROM " << m_outgoingTable << " " << whereClause.str();
216   eventQuery
217     << "DELETE FROM " << m_eventTable << " " << whereClause.str();
218 
219   PostgreSQLQuery incoming( incomingQuery.str() );
220   PostgreSQLQuery outgoing( outgoingQuery.str() );
221   PostgreSQLQuery event( eventQuery.str() );
222   m_pConnection->execute( incoming );
223   m_pConnection->execute( outgoing );
224   m_pConnection->execute( event );
225 }
226 
backup()227 void PostgreSQLLog::backup()
228 {
229 }
230 
insert(const std::string & table,const std::string value)231 void PostgreSQLLog::insert( const std::string& table, const std::string value )
232 {
233   UtcTimeStamp time;
234   int year, month, day, hour, minute, second, millis;
235   time.getYMD( year, month, day );
236   time.getHMS( hour, minute, second, millis );
237 
238   char sqlTime[ 24 ];
239   STRING_SPRINTF( sqlTime, "%d-%02d-%02d %02d:%02d:%02d.%003d",
240            year, month, day, hour, minute, second, millis );
241 
242   char* valueCopy = new char[ (value.size() * 2) + 1 ];
243   PQescapeString( valueCopy, value.c_str(), value.size() );
244 
245   std::stringstream queryString;
246   queryString << "INSERT INTO " << table << " "
247   << "(time, beginstring, sendercompid, targetcompid, session_qualifier, text) "
248   << "VALUES ("
249   << "'" << sqlTime << "',";
250 
251   if( m_pSessionID )
252   {
253     queryString
254     << "'" << m_pSessionID->getBeginString().getValue() << "',"
255     << "'" << m_pSessionID->getSenderCompID().getValue() << "',"
256     << "'" << m_pSessionID->getTargetCompID().getValue() << "',";
257     if( m_pSessionID->getSessionQualifier() == "" )
258       queryString << "NULL" << ",";
259     else
260       queryString << "'" << m_pSessionID->getSessionQualifier() << "',";
261   }
262   else
263   {
264     queryString << "NULL, NULL, NULL, NULL, ";
265   }
266 
267   queryString << "'" << valueCopy << "')";
268   delete [] valueCopy;
269 
270   PostgreSQLQuery query( queryString.str() );
271   m_pConnection->execute( query );
272 }
273 
274 } // namespace FIX
275 
276 #endif //HAVE_POSTGRESQL
277