Belle II Software  release-05-02-19
DBObjectLoader.cc
1 #include "daq/slc/database/DBObjectLoader.h"
2 
3 #include <daq/slc/system/LogFile.h>
4 
5 #include <daq/slc/base/StringUtil.h>
6 #include <daq/slc/base/ConfigFile.h>
7 #include <daq/slc/database/DBHandlerException.h>
8 
9 #include <iostream>
10 #include <sstream>
11 #include <cstdio>
12 #include <cstdlib>
13 #include <stdexcept>
14 #include <daq/slc/system/LockGuard.h>
15 
16 using namespace Belle2;
17 
18 Mutex DBObjectLoader::m_mutex;
19 
20 DBObject DBObjectLoader::load(const std::string& filename)
21 {
22  ConfigFile config(filename);
23  return load(config);
24 }
25 
26 DBObject DBObjectLoader::load(ConfigFile& config)
27 {
28  const std::string nodename = config.get("nodename");
29  const std::string configname = config.get("config");
30  DBObject obj;
31  if (nodename.size() > 0)
32  obj.setName(nodename + "@" + configname);
33  else
34  obj.setName(configname);
35  for (StringList::iterator it = config.getLabels().begin();
36  it != config.getLabels().end(); it++) {
37  const std::string name = *it;
38  StringList str = StringUtil::split(name, '.');
39  if (str[0] == "config") continue;
40  if (str[0] == "nodename") continue;
41  std::string value = config.get(name);
42  std::string::size_type pos = value.find_first_of("(");
43  DBField::Type type = DBField::TEXT;
44  if (pos != std::string::npos) {
45  std::string type_s = value.substr(0, pos);
46  if (type_s == "bool") type = DBField::BOOL;
47  else if (type_s == "int") type = DBField::INT;
48  else if (type_s == "float") type = DBField::FLOAT;
49  else if (type_s == "double") type = DBField::DOUBLE;
50  else if (type_s == "object") type = DBField::OBJECT;
51  if (type != DBField::TEXT) {
52  value = StringUtil::replace(value.substr(pos + 1), ")", "");
53  }
54  } else {
55  float vf;
56  if (StringUtil::tolower(value) == "true") {
57  type = DBField::BOOL;
58  } else if (StringUtil::tolower(value) == "false") {
59  type = DBField::BOOL;
60  } else if ((value.size() >= 2 && value.at(0) == '0' && value.at(1) == 'x') ||
61  StringUtil::isdigit(value)) {
62  type = DBField::INT;
63  } else if (StringUtil::split(value, '.').size() < 3 &&
64  StringUtil::isdigit(StringUtil::replace(value, ".", "")) &&
65  sscanf(value.c_str(), "%f", &vf) == 1) {
66  type = DBField::DOUBLE;
67  } else {
68  type = DBField::TEXT;
69  }
70  }
71  if (!setObject(obj, str, type, value)) {
72  LogFile::error("error : %s : %s", name.c_str(), value.c_str());
73  }
74  }
75  return obj;
76 }
77 
78 DBObject DBObjectLoader::load(DBInterface& db,
79  const std::string& tablename,
80  const std::string& config_in, bool isfull)
81 {
82  std::string configname = config_in;
83  if (!db.isConnected()) {
84  db.connect();
85  }
86  DBObject obj;
87  StringList list = DBObjectLoader::getDBlist(db, tablename, configname);
88  if (list.size() == 0) return obj;
89  StringList s = StringUtil::split(list[0], ',');
90  DBRecordList record_v;
91  std::stringstream ss;
92  ss << "select * from " << s[1] << " where pid =" << s[2] << " order by id";
93  try {
94  LockGuard lockGuard(m_mutex);
95  db.execute(ss.str());
96  record_v = db.loadRecords();
97  } catch (const DBHandlerException& e) {
98  throw;
99  }
100  int timestamp = 0;
101  if (list.size() > 0) {
102  configname = s[0];
103  timestamp = atoi(s[4].c_str());
104  }
105  ss.str("");
106  ss << " config : " << configname << std::endl;
107  for (size_t i = 0; i < record_v.size(); i++) {
108  DBRecord& record(record_v[i]);
109  if (record.hasField("value_b")) {
110  ss << record.get("name") << " : " <<
111  (record.getBool("value_b") ? "true" : "false") << std::endl;
112  } else if (record.hasField("value_i")) {
113  ss << record.get("name") << " : int(" << record.get("value_i") << ")" << std::endl;
114  } else if (record.hasField("value_f")) {
115  ss << record.get("name") << " : double(" << record.get("value_f") << ")" << std::endl;
116  } else if (record.hasField("value_t")) {
117  ss << record.get("name") << " : \"" << record.get("value_t") << "\"" << std::endl;
118  }
119  }
120  ConfigFile conf(ss);
121  obj = DBObjectLoader::load(conf);
122  obj.setDate(timestamp);
123  return obj;
124 }
125 
126 bool DBObjectLoader::add(DBObject& obj, StringList& str,
127  const std::string& name_in, const DBObject& cobj)
128 {
129  std::string name = str[0];
130  int index = 0;
131  StringList sstr = StringUtil::split(str[0], '[');
132  if (sstr.size() > 1) {
133  index = atoi(sstr[1].c_str());
134  name = sstr[0];
135  } else {
136  name = str[0];
137  index = 0;
138  }
139  if (str.size() > 1) {
140  str.erase(str.begin());
141  if (obj.hasObject(name)) {
142  return add(obj.getObject(name, index), str, name_in, cobj);
143  }
144  throw (std::out_of_range(StringUtil::form("%s:%d %s", __FILE__, __LINE__,
145  name.c_str())));
146  } else {
147  if (obj.hasObject(name) && obj.getNObjects(name) > index) {
148  obj.getObject(name, index).addObject(name_in, cobj);
149  return true;
150  }
151  obj.addObject(name, cobj);
152  return true;
153  }
154  throw (std::out_of_range(StringUtil::form("%s:%d %s", __FILE__, __LINE__,
155  StringUtil::join(str, ".").c_str())));
156 }
157 
158 bool DBObjectLoader::setObject(DBObject& obj, StringList& str,
159  DBField::Type type, const std::string& value,
160  const std::string& table_in, const std::string& config_in,
161  DBInterface* db)
162 {
163  std::string name;
164  int index = 0;
165  if (str.size() > 0) {
166  StringList sstr = StringUtil::split(str[0], '[');
167  if (sstr.size() > 1) {
168  index = atoi(sstr[1].c_str());
169  name = sstr[0];
170  } else {
171  name = str[0];
172  index = 0;
173  }
174  } else {
175  return false;
176  }
177  if (str.size() > 1) {
178  str.erase(str.begin());
179  bool found = obj.hasObject(name);
180  if (found) {
181  DBObjectList& objs(obj.getObjects(name));
182  for (DBObjectList::iterator it = objs.begin();
183  it != objs.end(); it++) {
184  if (it->getIndex() == index) {
185  found = false;
186  break;
187  }
188  }
189  found = !found;
190  }
191  if (!found) {
192  DBObject cobj;
193  cobj.setName(name);
194  cobj.setIndex(index);
195  obj.addObject(name, cobj);
196  }
197  DBObjectList& objs(obj.getObjects(name));
198  for (DBObjectList::iterator it = objs.begin();
199  it != objs.end(); it++) {
200  DBObject& cobj(*it);
201  if (cobj.getIndex() == index) {
202  return setObject(cobj, str, type, value, table_in, config_in, db);
203  }
204  }
205  } else {
206  switch (type) {
207  case DBField::BOOL: obj.addBool(name, false); break;
208  case DBField::INT: obj.addInt(name, 0); break;
209  case DBField::FLOAT: obj.addFloat(name, 0); break;
210  case DBField::DOUBLE: obj.addDouble(name, 0); break;
211  case DBField::TEXT: obj.addText(name, value); break;
212  case DBField::OBJECT: {
213  DBObject cobj(value);
214  std::string config_out = config_in;
215  //LogFile::notice(config_out);
216  if (db) {
217  StringList list = DBObjectLoader::getDBlist(*db, table_in, config_out);
218  if (list.size() > 0) {
219  //LogFile::notice("%s:%d", __FILE__, __LINE__);
220  bool found = false;
221  for (size_t i = 0; i < list.size(); i++) {
222  if (config_out == list[0]) {
223  found = true;
224  break;
225  }
226  }
227  if (found) {
228  cobj = DBObjectLoader::load(*db, table_in, config_out, true);
229  } else {
230  if (list.size() > 0) {
231  config_out = list[0];
232  cobj = DBObjectLoader::load(*db, table_in, config_out, true);
233  }
234  }
235  }
236  }
237  if (cobj.hasObject(name)) {
238  cobj.getObject(name).setPath(table_in + "/" + config_out);
239  obj.addObjects(name, cobj.getObjects(name));
240  } else {
241  cobj.setName(name);
242  obj.addObject(name, cobj);
243  }
244  } break;
245  default : return false;
246  }
247  obj.setValueText(name, value);
248  return true;
249  }
250  return false;
251 }
252 
253 bool DBObjectLoader::createDB(DBInterface& db,
254  const std::string& tablename,
255  const DBObject& obj)
256 {
257  std::string tablename_date = tablename + "_" + Date().toString("%Y");
258  std::string tablename_id = tablename + "_id";
259  try {
260  if (!db.isConnected()) db.connect();
261  } catch (const DBHandlerException& e) {
262  LogFile::error(e.what());
263  return false;
264  }
265  try {
266  if (obj.getName().size() == 0) {
267  LogFile::error("Configname is null. createDB canceled.");
268  return false;
269  }
270  if (!db.checkTable("daqconfig")) {
271  db.execute("create table daqconfig \n"
272  "(name text not null, \n"
273  "id bigserial, lastupdate timestamp, \n"
274  "UNIQUE(name));");
275  db.execute("create index daqconfig_id_index on daqconfig(id);",
276  tablename.c_str(), tablename.c_str());
277  }
278  if (!db.checkTable(tablename_id)) {
279  try {
280  db.execute("insert into daqconfig (name, lastupdate) values "
281  "('%s', current_timestamp);", tablename_id.c_str());
282  } catch (const std::exception& e) {
283  db.execute("update daqconfig set lastupdate = current_timestamp where name = '%s';",
284  tablename_id.c_str());
285  }
286  db.execute("create table %s \n"
287  "(name text not null \n"
288  "check (replace(name, '.', '') = name) not null, \n"
289  "id bigserial, \n"
290  "content text, \n"
291  "record_time timestamp with time zone default current_timestamp, \n"
292  "UNIQUE (name)); ", tablename_id.c_str());
293  }
294  if (!db.checkTable(tablename_date)) {
295  try {
296  db.execute("insert into daqconfig (name, lastupdate) values "
297  "('%s', current_timestamp);", tablename_date.c_str());
298  } catch (const std::exception& e) {
299  db.execute("update daqconfig set lastupdate = current_timestamp where name = '%s';",
300  tablename_date.c_str());
301  }
302  db.execute("create table %s \n"
303  "(name text not null,\n"
304  "id bigserial, \n"
305  "pid bigint, \n"
306  "value_b boolean default NULL, \n"
307  "value_i int default NULL, \n"
308  "value_f float default NULL, \n"
309  "value_t text default NULL \n"
310  "); ", tablename_date.c_str());
311  db.execute("create index %s_index on %s(id);",
312  tablename_date.c_str(), tablename_date.c_str());
313  }
314  } catch (const DBHandlerException& e) {
315  LogFile::warning(e.what());
316  }
317  try {
318  db.execute("begin;");
319  bool failed = true;
320  int id = 1;
321  try {
322  db.execute("insert into %s (name, content) values ('%s','%s') returning id;",
323  tablename_id.c_str(), obj.getName().c_str(), tablename_date.c_str());
324  failed = false;
325  DBRecordList record(db.loadRecords());
326  if (record.size() > 0) {
327  id = record[0].getInt("id");
328  }
329  } catch (const DBHandlerException& e) {
330  LogFile::error(e.what());
331  }
332  db.execute("commit;");
333  if (failed) return false;
334  std::string s = obj.printSQL(tablename_date, id);
335  db.execute(s);
336  } catch (const DBHandlerException& e) {
337  LogFile::error(e.what());
338  return false;
339  }
340  return true;
341 }
342 
343 StringList DBObjectLoader::getDBlist(DBInterface& db,
344  const std::string& tablename,
345  const std::string& grep, int max)
346 {
347  StringList str;
348  try {
349  if (!db.isConnected()) db.connect();
350  std::stringstream ss;
351  if (grep.size() > 0) {
352  const char* prefix = grep.c_str();
353  ss << "select id,name,content,to_char(record_time,'DD/MM HH24:MI:SS') as tdate, extract(epoch from record_time) as utime from " <<
354  tablename << "_id where "
355  << "(name like '" << prefix << "_%' or "
356  << "name like '" << prefix << "') order by id desc";
357  if (max > 0) ss << " limit " << max;
358  ss << ";";
359  } else {
360  ss << "select id,name,content,to_char(record_time,'DD/MM HH24:MI:SS') as tdate, extract(epoch from record_time) as utime from " <<
361  tablename << "_id order by id desc";
362  if (max > 0) ss << " limit " << max;
363  ss << ";";
364  }
365  LockGuard lockGuard(m_mutex);
366  db.execute(ss.str());
367  DBRecordList record_v(db.loadRecords());
368  for (size_t i = 0; i < record_v.size(); i++) {
369  DBRecord& record(record_v[i]);
370  str.push_back(record.get("name") + "," + record.get("content") + "," +
371  record.get("id") + "," + record.get("tdate") + "," + record.get("utime"));
372  }
373  } catch (const DBHandlerException& e) {
374  LogFile::error(e.what());
375  }
376  return str;
377 }
Belle2::DBHandlerException
Definition: DBHandlerException.h:12
prepareAsicCrosstalkSimDB.e
e
aux.
Definition: prepareAsicCrosstalkSimDB.py:53
Belle2::DBObject
Definition: DBObject.h:14
Belle2::Mutex
Definition: Mutex.h:12
Belle2::GenericLockGuard
Lock Guard for a Mutex instance.
Definition: LockGuard.h:40
Belle2::DBRecord
Definition: DBRecord.h:16
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::Date
Definition: Date.h:12
Belle2::DBInterface
Definition: DBInterface.h:19
Belle2::ConfigFile
Definition: ConfigFile.h:15