QwAnalysis
QwDatabase.cc
Go to the documentation of this file.
1 /*!
2  * \file QwDatabase.cc
3  * \brief A class for handling connections to the Qweak database.
4  *
5  * \author Damon Spayde
6  * \date 2010-01-07
7  */
8 
9 
10 #include "QwDatabase.h"
11 
12 // System headers
13 
14 // Qweak headers
15 
16 sql_create_6(db_schema, 1, 2
17  , mysqlpp::sql_int_unsigned , db_schema_id
18  , mysqlpp::sql_char , major_release_number
19  , mysqlpp::sql_char , minor_release_number
20  , mysqlpp::sql_char , point_release_number
21  , mysqlpp::sql_timestamp , time
22  , mysqlpp::Null<mysqlpp::sql_text> , script_name
23 )
24 
25 
26 /*! The simple constructor initializes member fields. This class is not
27  * used to establish the database connection. It sets up a
28  * mysqlpp::Connection() object that has exception throwing disabled.
29  */
30 //QwDatabase::QwDatabase() : Connection(false)
31 QwDatabase::QwDatabase(const string &major, const string &minor, const string &point) : Connection(), kValidVersionMajor(major), kValidVersionMinor(minor), kValidVersionPoint(point)
32 {
33  QwDebug << "Greetings from QwDatabase simple constructor." << QwLog::endl;
34 
35  // Initialize member fields
36  fDatabase=fDBServer=fDBUsername=fDBPassword="";
37  fVersionMajor=fVersionMinor=fVersionPoint="";
38 
39  fAccessLevel = kQwDatabaseOff;
40 
41  fDBPortNumber = 0;
42  fValidConnection = false;
43 
44 }
45 
46 /*! The constructor initializes member fields using the values in
47  * the QwOptions object.
48  * @param options The QwOptions object.
49  * @param major Major version number
50  * @param minor Minor version number
51  * @param point Point revision number
52  */
53 QwDatabase::QwDatabase(QwOptions &options, const string &major, const string &minor, const string &point) : Connection(), kValidVersionMajor(major), kValidVersionMinor(minor), kValidVersionPoint(point)
54 {
55  QwDebug << "Greetings from QwDatabase extended constructor." << QwLog::endl;
56 
57  // Initialize member fields
60 
62 
63  fDBPortNumber = 0;
64  fValidConnection = false;
65 
66  ProcessOptions(options);
67 
68 }
69 
70 /*! The destructor says "Good-bye World!"
71  */
73 {
74  QwDebug << "QwDatabase::~QwDatabase() : Good-bye World from QwDatabase destructor!" << QwLog::endl;
75  if( connected() ) Disconnect();
76 }
77 
78 /*! This function is used to load the connection information for the
79  * database. It tests the connection to make sure it is valid and causes a
80  * program exit if no valid connection can be formed.
81  *
82  * It is called the first time Connect() is called.
83  */
85 {
86  QwDebug << "Entering QwDatabase::ValidateConnection()..." << QwLog::endl;
87 
88  // Bool_t status;
89  //
90  // Retrieve options if they haven't already been filled.
91  //
92  // if (fDatabase.empty()){
93  // status = ProcessOptions(gQwOptions);
94  // if (!status) return status;
95  // }
96 
97  // Check values.
99  if (fDatabase.empty()){
100  QwError << "QwDatabase::ValidateConnection() : No database supplied. Unable to connect." << QwLog::endl;
101  fValidConnection=false;
102  }
103  if (fDBUsername.empty()){
104  QwError << "QwDatabase::ValidateConnection() : No database username supplied. Unable to connect." << QwLog::endl;
105  fValidConnection=false;
106  }
107  if (fDBPassword.empty()){
108  QwError << "QwDatabase::ValidateConnection() : No database password supplied. Unable to connect." << QwLog::endl;
109  fValidConnection=false;
110  }
111  if (fDBServer.empty()){
112  QwMessage << "QwDatabase::ValidateConnection() : No database server supplied. Attempting localhost." << QwLog::endl;
113  fDBServer = "localhost";
114  }
115  //
116  // Try to connect with given information
117  //
118  try {
119  connect(fDatabase.c_str(), fDBServer.c_str(), fDBUsername.c_str(),
120  fDBPassword.c_str(), (unsigned int) fDBPortNumber);
121  // connect(dbname.Data(), server.Data(), username.Data(), password.Data(), (unsigned int) port);
122  } catch (std::exception const& e) {
123  QwError << "QwDatabase::ValidateConnection() : " << QwLog::endl;
124  QwError << e.what() << " while validating connection" << QwLog::endl;
125  QwError << "Database name = " << fDatabase <<QwLog::endl;
126  QwError << "Database server = " << fDBServer <<QwLog::endl;
127  QwError << "Database username = " << fDBUsername <<QwLog::endl;
128  QwError << "Database port = " << fDBPortNumber <<QwLog::endl;
129  QwError << "Continuing without database." << QwLog::endl;
130  QwWarning << "Might have left database connection dangling..." << QwLog::endl;
132  return kFALSE;
133  }
134 
135  QwDebug << "QwDatabase::ValidateConnection() : Made it past connect() call." << QwLog::endl;
136 
137  // Get database schema version information
138  if (StoreDBVersion()) {
139  fValidConnection=true;
140  // Success!
141  QwMessage << "QwDatabase::ValidateConnection() : Successfully connected to requested database." << QwLog::endl;
142  } else {
143  QwError << "QwDatabase::ValidateConnection() : Unsuccessfully connected to requested database." << QwLog::endl;
144  // Connection was bad so clear the member variables
145  fValidConnection=false;
146  fDatabase.clear();
147  fDBServer.clear();
148  fDBUsername.clear();
149  fDBPassword.clear();
150  fDBPortNumber=0;
151  }
152  disconnect();
153  }
154 
155  // Check to make sure database and QwDatabase schema versions match up.
160  fValidConnection = false;
161  QwError << "QwDatabase::ValidConnection() : Connected database schema inconsistent with current version of analyzer." << QwLog::endl;
162  QwError << " Database version is " << this->GetVersion() << QwLog::endl;
163  QwError << " Required database version is " << this->GetValidVersion() << QwLog::endl;
164  QwError << " Please connect to a database supporting the required schema version." << QwLog::endl;
165  exit(1);
166  }
167 
168  QwDebug << "QwDatabase::ValidateConnection() : Exiting successfully." << QwLog::endl;
169  return fValidConnection;
170 }
171 
172 
173 /*! This function is used to initiate a database connection.
174  */
176 {
177  /* Open a connection to the database using the predefined parameters.
178  * Must call QwDatabase::ConnectionInfo() first.
179  */
180 
181  // Return flase, if we're not using the DB.
182  if (fAccessLevel==kQwDatabaseOff) return false;
183 
184  // Make sure not already connected
185  if (connected()) return true;
186 
187  // If never connected before, then make sure connection parameters form
188  // valid connection
189  if (!fValidConnection) {
191  }
192 
193  if (fValidConnection) {
194  return connect(fDatabase.c_str(), fDBServer.c_str(), fDBUsername.c_str(), fDBPassword.c_str(), (unsigned int) fDBPortNumber);
195  // return connect(fDatabase.Data(), fDBServer.Data(), fDBUsername.Data(), fDBPassword.Data(), (unsigned int) fDBPortNumber);
196  } else {
197  QwError << "QwDatabase::Connect() : Must establish valid connection to database." << QwLog::endl;
198  return false;
199  }
200 }
201 
202 /*!
203  * Defines configuration options for QwDatabase class using QwOptions
204  * functionality.
205  *
206  * Should apparently by called by QwOptions::DefineOptions() in
207  * QwParityOptions.h
208  */
210 {
211  // Specify command line options for use by QwDatabase
212  options.AddOptions("Database options")("QwDatabase.accesslevel", po::value<string>(), "database access level (OFF,RO,RW)");
213  options.AddOptions("Database options")("QwDatabase.dbname", po::value<string>(), "database name");
214  options.AddOptions("Database options")("QwDatabase.dbserver", po::value<string>(), "database server name");
215  options.AddOptions("Database options")("QwDatabase.dbusername", po::value<string>(), "database username");
216  options.AddOptions("Database options")("QwDatabase.dbpassword", po::value<string>(), "database password");
217  options.AddOptions("Database options")("QwDatabase.dbport", po::value<int>()->default_value(0), "database server port number (defaults to standard mysql port)");
218 }
219 
220 /*!
221  * Loads the configuration options for QwDatabase class into this instance of
222  * QwDatabase from the QwOptions object.
223  * @param options Options object
224  */
226 {
227  if (options.HasValue("QwDatabase.accesslevel")) {
228  string access = options.GetValue<string>("QwDatabase.accesslevel");
229  SetAccessLevel(access);
230  }
231  else {
232  QwWarning << "QwDatabase::ProcessOptions : No access level specified; database access is OFF" << QwLog::endl;
234  }
235  if (options.HasValue("QwDatabase.dbport")) {
236  fDBPortNumber = options.GetValue<int>("QwDatabase.dbport");
237  }
238  if (options.HasValue("QwDatabase.dbname")) {
239  fDatabase = options.GetValue<string>("QwDatabase.dbname");
240  }
241  if (options.HasValue("QwDatabase.dbusername")) {
242  fDBUsername = options.GetValue<string>("QwDatabase.dbusername");
243  }
244  if (options.HasValue("QwDatabase.dbpassword")) {
245  fDBPassword = options.GetValue<string>("QwDatabase.dbpassword");
246  }
247  if (options.HasValue("QwDatabase.dbserver")) {
248  fDBServer = options.GetValue<string>("QwDatabase.dbserver");
249  }
250 
251  return;
252 }
253 
254 void QwDatabase::ProcessOptions(const TString& dbname, const TString& username, const TString& passwd, const TString& dbhost, const Int_t dbport, const TString& accesslevel)
255 {
256  SetAccessLevel(static_cast<string>(accesslevel));
257  fDatabase = dbname;
258  fDBUsername = username;
259  fDBPassword = passwd;
260  fDBServer = dbhost;
261  fDBPortNumber = dbport;
262 }
263 
264 void QwDatabase::SetAccessLevel(string accesslevel)
265 {
266  TString level = accesslevel.c_str();
267  level.ToLower();
268  if (level=="off") fAccessLevel = kQwDatabaseOff;
269  else if (level=="ro") fAccessLevel = kQwDatabaseReadOnly;
270  else if (level=="rw") fAccessLevel = kQwDatabaseReadWrite;
271  else{
272  QwWarning << "QwDatabase::SetAccessLevel : Unrecognized access level \""
273  << accesslevel << "\"; setting database access OFF"
274  << QwLog::endl;
276  }
277  return;
278 }
279 
280 /*!
281  * This function prints the server information.
282  */
284 {
285  if (fValidConnection)
286  {
287  printf("\nQwDatabase MySQL ");
288  printf("%s v%s %s -----------------\n", BOLD, GetServerVersion().c_str(), NORMAL);
289  printf("Database server : %s%10s%s", RED, fDBServer.c_str(), NORMAL);
290  printf(" name : %s%12s%s", BLUE, fDatabase.c_str(), NORMAL);
291  printf(" user : %s%6s%s", RED, fDBUsername.c_str(), NORMAL);
292  printf(" port : %s%6d%s\n", BLUE, fDBPortNumber, NORMAL);
293  printf(" %s\n\n", server_status().c_str());
294  }
295  else
296  {
297  printf("There is no connection.\n");
298  }
299 
300  return;
301 }
302 
303 
304 const string QwDatabase::GetVersion(){
305  string version = fVersionMajor + "." + fVersionMinor + "." + fVersionPoint;
306  return version;
307 }
308 
310  string version = kValidVersionMajor + "." + kValidVersionMinor + "." + kValidVersionPoint;
311  return version;
312 }
313 
314 /*
315  * Retrieves database schema version information from database.
316  * Returns true if successful, false otherwise.
317  */
319 {
320  try
321  {
322  mysqlpp::Query query = this->Query();
323 
324  query << "SELECT * FROM db_schema";
325  std::vector<db_schema> res;
326  query.storein(res);
327  QwDebug << "QwDatabase::StoreDBVersion => Number of rows returned: " << res.size() << QwLog::endl;
328 
329  // If there is more than one run in the DB with the same run number, then there will be trouble later on. Catch and bomb out.
330  if (res.size()>1)
331  {
332  QwError << "Unable to find unique schema version in database." << QwLog::endl;
333  QwError << "Schema query returned " << res.size() << "rows." << QwLog::endl;
334  QwError << "Please make sure that db_schema contains one unique." << QwLog::endl;
335  this->Disconnect();
336  return false;
337  }
338 
339  // Run already exists in database. Pull run_id and move along.
340  if (res.size()==1)
341  {
342  QwDebug << "QwDatabase::StoreDBVersion => db_schema_id = " << res.at(0).db_schema_id << QwLog::endl;
343 
344  fVersionMajor=res.at(0).major_release_number;
345  fVersionMinor=res.at(0).minor_release_number;
346  fVersionPoint=res.at(0).point_release_number;
347  this->Disconnect();
348  }
349  }
350  catch (const mysqlpp::Exception& er)
351  {
352  QwError << er.what() << QwLog::endl;
353  disconnect();
354  return false;
355  }
356 
357  return true;
358 
359 }
#define QwMessage
Predefined log drain for regular messages.
Definition: QwLog.h:50
UInt_t fDBPortNumber
Port number to connect to on server (mysql default port is 3306)
Definition: QwDatabase.h:97
Bool_t ValidateConnection()
Checks that given connection parameters result in a valid connection.
Definition: QwDatabase.cc:84
QwDatabase(const string &major="00", const string &minor="00", const string &point="0000")
Simple constructor.
const string kValidVersionPoint
Definition: QwDatabase.h:105
void Disconnect()
Definition: QwDatabase.h:59
Bool_t Connect()
Open a connection to the database using the predefined parameters.
Definition: QwDatabase.cc:175
void ProcessOptions(QwOptions &options)
Processes the options contained in the QwOptions object.
Definition: QwDatabase.cc:225
An options class.
Definition: QwOptions.h:133
A database interface class.
Definition: QwDatabase.h:45
bool HasValue(const std::string &key)
Has this key been defined.
Definition: QwOptions.h:233
#define BOLD
Definition: QwColor.h:37
string fDBServer
Name of server carrying DB to connect to.
Definition: QwDatabase.h:94
const string GetValidVersion()
Definition: QwDatabase.cc:309
virtual ~QwDatabase()
Destructor.
Definition: QwDatabase.cc:72
A class for handling connections to the Qweak database.
void SetAccessLevel(string accesslevel)
Sets the access level flag based on string labels: &quot;off&quot;, &quot;ro&quot;, &quot;rw&quot;.
Definition: QwDatabase.cc:264
static const double e
Definition: QwUnits.h:91
string fVersionMajor
Major version number of current DB schema.
Definition: QwDatabase.h:100
const string GetVersion()
Definition: QwDatabase.cc:304
EQwDBAccessLevel fAccessLevel
Access level of the database instance.
Definition: QwDatabase.h:91
po::options_description_easy_init AddOptions(const std::string &blockname="Specialized options")
Add an option to a named block or create new block.
Definition: QwOptions.h:164
const string kValidVersionMajor
Definition: QwDatabase.h:103
T GetValue(const std::string &key)
Get a templated value.
Definition: QwOptions.h:240
#define QwDebug
Predefined log drain for debugging output.
Definition: QwLog.h:60
string fDBPassword
DB account password.
Definition: QwDatabase.h:96
const string kValidVersionMinor
Definition: QwDatabase.h:104
Bool_t fValidConnection
True if a valid connection was established using defined connection information.
Definition: QwDatabase.h:98
string fVersionPoint
Point version number of current DB schema.
Definition: QwDatabase.h:102
mysqlpp::Query Query(const char *qstr=0)
Definition: QwDatabase.h:66
string fDBUsername
Name of account to connect to DB server with.
Definition: QwDatabase.h:95
void PrintServerInfo()
Definition: QwDatabase.cc:283
#define RED
Definition: QwColor.h:29
sql_create_6(db_schema, 1, 2, mysqlpp::sql_int_unsigned, db_schema_id, mysqlpp::sql_char, major_release_number, mysqlpp::sql_char, minor_release_number, mysqlpp::sql_char, point_release_number, mysqlpp::sql_timestamp, time, mysqlpp::Null< mysqlpp::sql_text >, script_name) QwDatabase
Definition: QwDatabase.cc:16
string fVersionMinor
Minor version number of current DB schema.
Definition: QwDatabase.h:101
string fDatabase
Name of database to connect to.
Definition: QwDatabase.h:93
#define BLUE
Definition: QwColor.h:32
static std::ostream & endl(std::ostream &)
End of the line.
Definition: QwLog.cc:299
const string GetServerVersion()
Definition: QwDatabase.h:61
#define NORMAL
Definition: QwColor.h:61
#define QwWarning
Predefined log drain for warnings.
Definition: QwLog.h:45
static void DefineOptions(QwOptions &options)
Defines available class options for QwOptions.
Definition: QwDatabase.cc:209
bool StoreDBVersion()
Retrieve database schema version information from database.
Definition: QwDatabase.cc:318
#define QwError
Predefined log drain for errors.
Definition: QwLog.h:40