VSQLManager_MySQL.cc
Go to the documentation of this file.
1 #include <det/VSQLManager_MySQL.h>
2 #include <utl/Reader.h>
3 #include <utl/AugerUnits.h>
4 #include <fwk/CentralConfig.h>
5 #include <fwk/CommandLineOptions.h>
6 
7 using namespace std;
8 using namespace utl;
9 
10 
11 namespace det {
12 
13  int VSQLManager::fgGlobalLogQueries = 0;
14 
15 
16  void
17  VSQLManager::Close()
18  {
19  if (fIsInitialized && fMySQL) {
20  const double time = fTime.GetTime();
21  if (time) {
22  ostringstream info;
23  info << "Total time spent for database '" << fDatabaseName
24  << "' queries is " << time/second << " sec.";
25  INFO(info);
26  }
27  FreeResult();
28  mysql_close(fMySQL);
29  fMySQL = nullptr;
30  }
31  if (fLogQueryStream) {
32  fLogQueryStream->close();
33  delete fLogQueryStream;
34  fLogQueryStream = nullptr;
35  }
36  fIsInitialized = false;
37  }
38 
39 
40  void
41  VSQLManager::Init(const std::string& configLink)
42  {
43  VManager::Init(configLink);
44 
45  fBranch.GetChild("databaseName").GetData(fDatabaseName);
46  fBranch.GetChild("softwareVersion").GetData(fDatabaseSoftwareVersion);
47  if (fgGlobalLogQueries) {
48  fLogQueries = fgGlobalLogQueries;
49  } else {
50  Branch logQueriesB = fBranch.GetChild("logQueries");
51  if (logQueriesB)
52  logQueriesB.GetData(fLogQueries);
53  }
54 
55  if (fLogQueries) {
56  ostringstream fname;
57  fname << "mysql-" << fDatabaseName << '-' << getpid() << ".query";
58  fLogQueryStream = new ofstream(fname.str().c_str());
59  if (fLogQueryStream)
60  INFO(string("Database queries will be logged into file '") +
61  fname.str() + "'.");
62  }
63  }
64 
65 
66  void
67  VSQLManager::Connect()
68  const
69  {
70  if (!fIsInitialized) {
71  const string err = "MySQL Manager not initialized.";
72  ERROR(err);
73  throw IOFailureException(err);
74  }
75 
76  if (fMySQL) {
77  WARNING("MySQL Manager already connected!");
78  return;
79  }
80 
82  Branch serverListB = cc.GetTopBranch("databaseServers");
83  if (!serverListB) {
84  const string err = "VSQLManager cannot access databaseServers configuration file!";
85  ERROR(err);
86  throw IOFailureException(err);
87  }
88 
89  for (Branch serverB = serverListB.GetChild("serverList").GetFirstChild();
90  serverB; serverB = serverB.GetNextSibling()) {
91 
92  const vector<string> hostName = serverB.GetChild("hostName").Get<vector<string>>();
93 
94  fDatabaseUserName = serverB.GetChild("userName").Get<string>();
95  fDatabasePassword = serverB.GetChild("password").Get<string>();
96  Branch portB = serverB.GetChild("port");
97  if (portB)
98  portB.GetData(fPort);
99  else
100  fPort = 3306;
101 
102  for (const auto& hn : hostName) {
103 
104  fDatabaseServer = hn;
105 
106  fMySQL = mysql_init(nullptr);
107  //mysql_options(fMySQL, MYSQL_OPT_CONNECT_TIMEOUT, "5");
108  if (mysql_real_connect(fMySQL, fDatabaseServer.c_str(),
109  fDatabaseUserName.c_str(),
110  fDatabasePassword.c_str(),
111  fDatabaseName.c_str(),
112  fPort, nullptr, 0)) {
113  ostringstream info;
114  info << "Connected to database '" << fDatabaseName << "' "
115  "on host " << mysql_get_host_info(fMySQL);
116  INFO(info);
117  if (fLogQueryStream)
118  *fLogQueryStream << "* * " << info.str() << endl;
119  fIsInitialized = true;
120  break;
121  }
122 
123  ostringstream info;
124  info << "Connection to the database '" << fDatabaseName << "' "
125  "on " << fDatabaseUserName /*<< ':' << fDatabasePassword*/
126  << '@' << fDatabaseServer << ':' << fPort <<" failed. "
127  "MySQL reports the following error: \"" << mysql_error(fMySQL) << "\". "
128  "Trying an alternative database configuration, if one has been specified...";
129  INFO(info);
130  if (fLogQueryStream) {
131  *fLogQueryStream << "* * " << info.str() << endl;
132  fLogQueryStream->close();
133  delete fLogQueryStream;
134  fLogQueryStream = nullptr;
135  }
136 
137  mysql_close(fMySQL);
138  fMySQL = nullptr;
139  fIsInitialized = false;
140 
141  }
142 
143  if (fIsInitialized)
144  break;
145 
146  }
147 
148  if (!fIsInitialized) {
149  ostringstream err;
150  err << "Could not connect to the requested database: '" << fDatabaseName
151  << "' on any of the specified hosts. Giving up.";
152  ERROR(err);
153  throw IOFailureException(err.str());
154  }
155  }
156 
157 
159  VSQLManager::Query(const string& query, const string& what)
160  const
161  {
162  if (!fMySQL)
163  Connect();
164 
165  fTime.Start();
166  const int ret = mysql_query(fMySQL, query.c_str());
167  const double elapsedTime = fTime.Stop();
168 
169  if (fLogQueryStream)
170  *fLogQueryStream << IsReportingErrors() << ' '
171  << elapsedTime/second << '\t' << query.c_str()
172  << (ret ? " -> FAILED\n" : " -> OK") << flush;
173 
174  if (ret) {
175  if (IsReportingErrors()) {
176  ostringstream err;
177  err << "Query '" << query << "' ";
178  if (!what.empty())
179  err << "for " << what << ' ';
180  err << "failed. "
181  "Reason: \"" << mysql_error(fMySQL) << '"';
182  ERROR(err);
183  }
184  return eNotFound;
185  }
186 
187  FreeResult();
188 
189  fMySQLResult = mysql_store_result(fMySQL);
190 
191  if (!fMySQLResult) {
192  if (fLogQueryStream)
193  *fLogQueryStream << ": NO_RESULT\n";
194  if (!what.empty() && IsReportingErrors()) {
195  ostringstream warn;
196  warn << "Query for " << what << " "
197  "returned no results.";
198  WARNING(warn);
199  }
200  return eNotFound;
201  }
202 
203  // log all rows
204  if (fLogQueryStream && fLogQueries > 1) {
205  *fLogQueryStream << ": (";
206  const int nCols = NumFields();
207  if (nCols) {
208  MYSQL_ROW row;
209  while ((row = FetchRow())) {
210  *fLogQueryStream << " ( ";
211  if (row[0])
212  *fLogQueryStream << '\'' << row[0] << '\'';
213  else
214  *fLogQueryStream << "NULL*";
215  for (int i = 1; i < nCols; ++i)
216  if (row[i])
217  *fLogQueryStream << ", '" << row[i] << '\'';
218  else
219  *fLogQueryStream << ", NULL*";
220  *fLogQueryStream << " )";
221  }
222  FreeResult();
223  // redo query since we used all rows
224  mysql_query(fMySQL, query.c_str());
225  fMySQLResult = mysql_store_result(fMySQL);
226  }
227  *fLogQueryStream << " )" << endl;
228  }
229 
230  return eFound;
231  }
232 
233 
234  string
235  VSQLManager::MergeIndexMap(const IndexMap& componentIndex)
236  {
237  VManager::IndexMap::const_iterator it = componentIndex.begin();
238  if (it == componentIndex.end())
239  return "";
240  ostringstream res;
241  res << it->first << " = " << it->second;
242  for (++it; it != componentIndex.end(); ++it)
243  res << " AND " << it->first << " = " << it->second;
244  return res.str();
245  }
246 
247 }
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
void Init()
Initialise the registry.
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
Base class to report exceptions in IO.
Branch GetNextSibling() const
Get next sibling of this branch.
Definition: Branch.cc:284
Class representing a document branch.
Definition: Branch.h:107
const double second
Definition: GalacticUnits.h:32
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
static CentralConfig * GetInstance()
Use this the first time you get an instance of central configuration.
std::map< std::string, std::string > IndexMap
Definition: VManager.h:133
Main configuration utility.
Definition: CentralConfig.h:51
Branch GetFirstChild() const
Get first child of this Branch.
Definition: Branch.cc:98
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)
Status
Specifies success or (eventually) various possible failure modes.
Definition: VManager.h:127

, generated on Tue Sep 26 2023.