LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
DatabaseUtil.cc
Go to the documentation of this file.
1 //
3 // DatabaseUtil_plugin
4 //
6 // Framework includes
7 
8 // C++ language includes
9 #include <fstream>
10 #include <iostream>
11 //#include <libpq-fe.h>
12 
13 // LArSoft includes
14 #include "cetlib_except/exception.h"
17 
18 //-----------------------------------------------
20 {
21  conn = NULL;
22  this->reconfigure(pset);
23  fChannelMap.clear();
24  fChannelReverseMap.clear();
25 }
26 
27 //----------------------------------------------
28 int util::DatabaseUtil::Connect(int conn_wait)
29 {
30  if (!fShouldConnect) return -1;
31 
32  if (conn_wait) sleep(conn_wait);
33 
34  conn = PQconnectdb(connection_str);
35  if (PQstatus(conn) == CONNECTION_BAD) {
36  mf::LogWarning("DatabaseUtil")
37  << "Connection to database failed, " << PQerrorMessage(conn) << "\n";
38  if ((strstr(PQerrorMessage(conn), "remaining connection slots are reserved") != NULL ||
39  strstr(PQerrorMessage(conn), "sorry, too many clients already") != NULL) &&
40  conn_wait < 20) {
41  conn_wait += 2;
42  mf::LogWarning("DatabaseUtil") << "retrying connection after " << conn_wait << " seconds \n";
43  return this->Connect(conn_wait);
44  }
45  if (fToughErrorTreatment) throw cet::exception("DataBaseUtil") << " DB connection failed\n";
46  }
47  else {
48  MF_LOG_DEBUG("DatabaseUtil") << "Connected OK\n";
49  return 1;
50  }
51  return -1;
52 }
53 
55 {
56  if (!fShouldConnect) return -1;
57  //close connection
58  MF_LOG_DEBUG("DatabaseUtil") << "Closing Connection \n";
59  PQfinish(conn);
60  return 1;
61 }
62 
63 //------------------------------------------------
65 {
66  fDBHostName = pset.get<std::string>("DBHostName");
67  fDBName = pset.get<std::string>("DBName");
68  fDBUser = pset.get<std::string>("DBUser");
69  fTableName = pset.get<std::string>("TableName");
70  fPort = pset.get<int>("Port");
71  fPassword = "";
72  fToughErrorTreatment = pset.get<bool>("ToughErrorTreatment");
73  fShouldConnect = pset.get<bool>("ShouldConnect");
74 
75  // constructor decides if initialized value is a path or an environment variable
76  std::string passfname;
77  cet::search_path sp("FW_SEARCH_PATH");
78  sp.find_file(pset.get<std::string>("PassFileName"), passfname);
79 
80  if (!passfname.empty()) {
81  std::ifstream in(passfname.c_str());
82  if (!in) {
84  << "Database password file '" << passfname
85  << "' not found in FW_SEARCH_PATH; using an empty password.\n";
86  }
87  std::getline(in, fPassword);
88  in.close();
89  }
90  else if (fShouldConnect) {
92  << "Database password file '" << pset.get<std::string>("PassFileName")
93  << "' not found in FW_SEARCH_PATH; using an empty password.\n";
94  }
95 
96  sprintf(connection_str,
97  "host=%s dbname=%s user=%s port=%d password=%s ",
98  fDBHostName.c_str(),
99  fDBName.c_str(),
100  fDBUser.c_str(),
101  fPort,
102  fPassword.c_str());
103 
104  return;
105 }
106 
107 int util::DatabaseUtil::SelectSingleFieldByQuery(std::vector<std::string>& value, const char* query)
108 {
109  PGresult* result;
110  char* string_val;
111 
112  if (this->Connect() == -1) {
113  if (fShouldConnect)
114  mf::LogWarning("DatabaseUtil") << "DB Connection error \n";
115  else
116  mf::LogInfo("DatabaseUtil") << "Not connecting to DB by choice. \n";
117  return -1;
118  }
119 
120  result = PQexec(conn, query);
121 
122  if (!result) {
123  mf::LogInfo("DatabaseUtil") << "PQexec command failed, no error code\n";
124  return -1;
125  }
126  else if (PQresultStatus(result) != PGRES_TUPLES_OK) {
127  if (PQresultStatus(result) == PGRES_COMMAND_OK)
128  MF_LOG_DEBUG("DatabaseUtil")
129  << "Command executed OK, " << PQcmdTuples(result) << " rows affected\n";
130  else
131  mf::LogWarning("DatabaseUtil")
132  << "Command failed with code " << PQresStatus(PQresultStatus(result)) << ", error message "
133  << PQresultErrorMessage(result) << "\n";
134 
135  PQclear(result);
136  this->DisConnect();
137  return -1;
138  }
139  else {
140  // mf::LogInfo("DatabaseUtil")<<"Query may have returned data\n";
141  // mf::LogInfo("DatabaseUtil")<<"Number of rows returned: "<<PQntuples(result)
142  // <<", fields: "<<PQnfields(result)<<" \n";
143 
144  if (PQntuples(result) >= 1) {
145  for (int i = 0; i < PQntuples(result); i++) {
146  string_val = PQgetvalue(result, i, 0);
147  value.push_back(string_val);
148  MF_LOG_DEBUG("DatabaseUtil") << " extracted value: " << value[i] << "\n";
149  }
150  PQclear(result);
151  this->DisConnect();
152  return 0;
153  }
154  else {
155  mf::LogWarning("DatabaseUtil")
156  << "wrong number of rows returned:" << PQntuples(result) << "\n";
157  PQclear(result);
158  this->DisConnect();
159  return -1;
160  }
161  }
162 }
163 
164 int util::DatabaseUtil::GetTemperatureFromDB(int run, double& temp_real)
165 {
166  std::vector<std::string> retvalue;
167  char cond[30];
168  sprintf(cond, "run = %d", run);
169  int err = SelectFieldByName(retvalue, "temp", cond, fTableName.c_str());
170 
171  if (err != -1 && retvalue.size() == 1) {
172  char* endstr;
173  temp_real = std::strtod(retvalue[0].c_str(), &endstr);
174  return 0;
175  }
176 
177  return -1;
178 }
179 
180 int util::DatabaseUtil::GetEfieldValuesFromDB(int run, std::vector<double>& efield)
181 {
182 
183  std::vector<std::string> retvalue;
184 
185  char query[200];
186  sprintf(query,
187  "SELECT EFbet FROM EField,%s WHERE Efield.FID = %s.FID AND run = %d ORDER BY planegap",
188  fTableName.c_str(),
189  fTableName.c_str(),
190  run);
191  int err = SelectSingleFieldByQuery(retvalue, query);
192 
193  if (err != -1 && retvalue.size() >= 1) {
194  efield.clear(); //clear value before setting new values
195  for (unsigned int i = 0; i < retvalue.size(); i++) {
196  char* endstr;
197  efield.push_back(std::strtod(retvalue[i].c_str(), &endstr));
198  }
199  return 0;
200  }
201 
202  return -1;
203 }
204 
205 int util::DatabaseUtil::SelectFieldByName(std::vector<std::string>& value,
206  const char* field,
207  const char* condition,
208  const char* table)
209 {
210 
211  char query[100];
212  sprintf(query, "SELECT %s FROM %s WHERE %s", field, table, condition);
213 
214  return SelectSingleFieldByQuery(value, query);
215 }
216 
217 int util::DatabaseUtil::GetLifetimeFromDB(int run, double& lftime_real)
218 {
219 
220  // char query[100];
221  // sprintf(query,"SELECT tau FROM argoneut_test WHERE run = %d",run);
222 
223  std::vector<std::string> retvalue;
224  char cond[30];
225  sprintf(cond, "run = %d", run);
226  int err = SelectFieldByName(retvalue, "tau", cond, fTableName.c_str());
227 
228  if (err != -1 && retvalue.size() == 1) {
229  char* endstr;
230  lftime_real = std::strtod(retvalue[0].c_str(), &endstr);
231  return 0;
232  }
233 
234  return -1;
235 }
236 
237 int util::DatabaseUtil::GetTriggerOffsetFromDB(int run, double& T0_real)
238 {
239 
240  // char query[100];
241  // sprintf(query,"SELECT tau FROM argoneut_test WHERE run = %d",run);
242 
243  std::vector<std::string> retvalue;
244  char cond[30];
245  sprintf(cond, "run = %d", run);
246  int err = SelectFieldByName(retvalue, "T0", cond, fTableName.c_str());
247 
248  if (err != -1 && retvalue.size() == 1) {
249  char* endstr;
250  T0_real = std::strtod(retvalue[0].c_str(), &endstr);
251  return 0;
252  }
253 
254  return -1;
255 }
256 
257 int util::DatabaseUtil::GetPOTFromDB(int run, long double& POT)
258 {
259 
260  // char query[100];
261  // sprintf(query,"SELECT tau FROM argoneut_test WHERE run = %d",run);
262 
263  std::vector<std::string> retvalue;
264  char cond[30];
265  sprintf(cond, "run = %d", run);
266  int err = SelectFieldByName(retvalue, "pot", cond, fTableName.c_str());
267 
268  if (err != -1 && retvalue.size() == 1) {
269  char* endstr;
270  POT = std::strtold(retvalue[0].c_str(), &endstr);
271  return 0;
272  }
273 
274  return -1;
275 }
276 
277 namespace util {
278 
279  void DatabaseUtil::LoadUBChannelMap(int data_taking_timestamp, int swizzling_timestamp)
280  {
281 
282  if (fChannelMap.size() > 0) {
283  // Use prevously grabbed data to avoid repeated call to database.
284  // Also this avoids inglorious segfault.
285  return;
286  }
287  if (conn == NULL) Connect(0);
288 
289  if (PQstatus(conn) != CONNECTION_OK) {
290  mf::LogError("") << __PRETTY_FUNCTION__
291  << ": Couldn't open connection to postgresql interface" << PQdb(conn) << ":"
292  << PQhost(conn);
293  PQfinish(conn);
295  << "Failed to get channel map from DB." << std::endl;
296  }
297 
298  fChannelMap.clear();
299  fChannelReverseMap.clear();
300 
301  PGresult* res = PQexec(conn, "BEGIN");
302  if (PQresultStatus(res) != PGRES_COMMAND_OK) {
303  mf::LogError("") << "postgresql BEGIN failed";
304  PQclear(res);
305  PQfinish(conn);
306  throw art::Exception(art::errors::FileReadError) << "postgresql BEGIN failed." << std::endl;
307  }
308 
309  // Jason St. John's updated call to versioned database.
310  // get_map_double_sec (data_taking_timestamp int DEFAULT now() ,
311  // swizzling_timestamp int DEFAULT now() )
312  // Returns rows of: crate, slot, fem_channel, larsoft_channel
313  // Both arguments are optional, or can be passed their default of now(), or can be passed an explicit timestamp:
314  // Example: "SELECT get_map_double_sec(1438430400);"
315  PQclear(res);
316 
317  char dbquery[200];
318  sprintf(
319  dbquery, "SELECT get_map_double_sec(%i,%i);", data_taking_timestamp, swizzling_timestamp);
320  res = PQexec(conn, dbquery);
321 
322  if ((!res) || (PQresultStatus(res) != PGRES_TUPLES_OK) || (PQntuples(res) < 1)) {
323  mf::LogError("") << "SELECT command did not return tuples properly. \n"
324  << PQresultErrorMessage(res) << "Number rows: " << PQntuples(res);
325  PQclear(res);
326  PQfinish(conn);
327  throw art::Exception(art::errors::FileReadError) << "postgresql SELECT failed." << std::endl;
328  }
329 
330  int num_records = PQntuples(res); //One record per channel, ideally.
331 
332  for (int i = 0; i < num_records; i++) {
333  std::string tup = PQgetvalue(res, i, 0); // (crate,slot,FEMch,larsoft_chan) format
334  tup = tup.substr(1, tup.length() - 2); // Strip initial & final parentheses.
335  std::vector<std::string> fields;
336  split(tup, ',', fields); // Explode substrings into vector with comma delimiters.
337 
338  int crate_id = atoi(fields[0].c_str());
339  int slot = atoi(fields[1].c_str());
340  int boardChan = atoi(fields[2].c_str());
341  int larsoft_chan = atoi(fields[3].c_str());
342 
343  UBDaqID daq_id(crate_id, slot, boardChan);
344  std::pair<UBDaqID, UBLArSoftCh_t> p(daq_id, larsoft_chan);
345 
346  if (fChannelMap.find(daq_id) != fChannelMap.end()) {
347  std::cout << __PRETTY_FUNCTION__ << ": ";
348  std::cout << "Multiple entries!" << std::endl;
349  mf::LogWarning("") << "Multiple DB entries for same (crate,card,channel). " << std::endl
350  << "Redefining (crate,card,channel)=>id link (" << daq_id.crate << ", "
351  << daq_id.card << ", " << daq_id.channel << ")=>"
352  << fChannelMap.find(daq_id)->second;
353  }
354 
355  fChannelMap.insert(p);
356  fChannelReverseMap.insert(std::pair<UBLArSoftCh_t, UBDaqID>(larsoft_chan, daq_id));
357  }
358  this->DisConnect();
359  } // end of LoadUBChannelMap
360 
361  UBChannelMap_t DatabaseUtil::GetUBChannelMap(int data_taking_timestamp, int swizzling_timestamp)
362  {
363  LoadUBChannelMap(data_taking_timestamp, swizzling_timestamp);
364  return fChannelMap;
365  }
366 
368  int swizzling_timestamp)
369  {
370  LoadUBChannelMap(data_taking_timestamp, swizzling_timestamp);
371  return fChannelReverseMap;
372  }
373 
374  // Handy, typical string-splitting-to-vector function.
375  // I hate C++ strong typing and string handling so very, very much.
376  std::vector<std::string>& DatabaseUtil::split(const std::string& s,
377  char delim,
378  std::vector<std::string>& elems)
379  {
380  std::stringstream ss(s);
381  std::string item;
382  while (std::getline(ss, item, delim)) {
383  elems.push_back(item);
384  }
385  return elems;
386  }
387 
388 }
int GetTriggerOffsetFromDB(int run, double &T0_real)
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:26
std::string fPassword
Definition: DatabaseUtil.h:87
int GetEfieldValuesFromDB(int run, std::vector< double > &efield)
std::string fDBName
Definition: DatabaseUtil.h:83
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
UBChannelMap_t GetUBChannelMap(int data_taking_timestamp=-1, int swizzling_timestamp=-1)
UBChannelReverseMap_t GetUBChannelReverseMap(int data_taking_timestamp=-1, int swizzling_timestamp=-1)
int SelectSingleFieldByQuery(std::vector< std::string > &value, const char *query)
std::string fDBHostName
Definition: DatabaseUtil.h:82
int GetPOTFromDB(int run, long double &POT)
T get(std::string const &key) const
Definition: ParameterSet.h:314
char connection_str[200]
Definition: DatabaseUtil.h:79
int GetLifetimeFromDB(int run, double &lftime_real)
DatabaseUtil(fhicl::ParameterSet const &pset)
Definition: DatabaseUtil.cc:19
pg_result PGresult
Definition: Table.h:19
double value
Definition: spectrum.C:18
std::map< UBDaqID, UBLArSoftCh_t > UBChannelMap_t
Definition: DatabaseUtil.h:46
void reconfigure(fhicl::ParameterSet const &pset)
Definition: DatabaseUtil.cc:64
std::string fTableName
Definition: DatabaseUtil.h:85
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
void LoadUBChannelMap(int data_taking_timestamp=-1, int swizzling_timestamp=-1)
ifstream in
Definition: comparison.C:7
int SelectFieldByName(std::vector< std::string > &value, const char *field, const char *condition, const char *table)
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
int Connect(int conn_wait=0)
Definition: DatabaseUtil.cc:28
#define MF_LOG_DEBUG(id)
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
std::map< UBLArSoftCh_t, UBDaqID > UBChannelReverseMap_t
Definition: DatabaseUtil.h:47
std::string fDBUser
Definition: DatabaseUtil.h:84
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
UBChannelReverseMap_t fChannelReverseMap
Definition: DatabaseUtil.h:92
int GetTemperatureFromDB(int run, double &temp_real)
UBChannelMap_t fChannelMap
Definition: DatabaseUtil.h:91