Belle II Software development
DBObject.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8#include "daq/slc/database/DBObject.h"
9
10#include <daq/slc/base/StringUtil.h>
11#include <daq/slc/base/Reader.h>
12#include <daq/slc/base/Writer.h>
13
14#include <cstdio>
15#include <cstdlib>
16#include <cstring>
17#include <sstream>
18
19using namespace Belle2;
20
21DBObject::DBObject()
22{
23 setDate(0);
24}
25
26DBObject::DBObject(const std::string& path)
27{
28 setDate(0);
29 setPath(path);
30}
31
32DBObject::DBObject(const DBObject& obj)
33 : AbstractDBObject(obj)
34{
35 copy(obj);
36}
37
38const DBObject& DBObject::operator=(const DBObject& obj)
39{
40 copy(obj);
41 return *this;
42}
43
44void DBObject::copy(const DBObject& obj)
45{
46 reset();
47 setDate(obj.getDate());
48 setIndex(obj.getIndex());
49 setId(obj.getId());
50 setPath(obj.getPath());
51 setName(obj.getName());
52 for (DBField::NameList::const_iterator it = obj.getFieldNames().begin();
53 it != obj.getFieldNames().end(); ++it) {
54 const std::string& name(*it);
55 DBField::Type type = obj.getProperty(name).getType();
56 switch (type) {
57 case DBField::BOOL: addBool(name, obj.getBool(name)); break;
58 case DBField::CHAR: addChar(name, obj.getChar(name)); break;
59 case DBField::SHORT: addShort(name, obj.getShort(name)); break;
60 case DBField::INT: addInt(name, obj.getInt(name)); break;
61 case DBField::LONG: addLong(name, obj.getLong(name)); break;
62 case DBField::FLOAT: addFloat(name, obj.getFloat(name)); break;
63 case DBField::DOUBLE: addDouble(name, obj.getDouble(name)); break;
64 case DBField::TEXT: addText(name, obj.getText(name)); break;
65 case DBField::OBJECT: addObjects(name, obj.getObjects(name)); break;
66 default: break;
67 }
68 }
69}
70
71DBObject::~DBObject()
72{
73 reset();
74}
75
76int DBObject::getNObjects(const std::string& name) const
77{
78 FieldObjectList::const_iterator it = m_obj_v_m.find(name);
79 if (it != m_obj_v_m.end()) return it->second.size();
80 return 0;
81}
82
83DBObjectList& DBObject::getObjects(const std::string& name)
84{
85 FieldObjectList::iterator it = m_obj_v_m.find(name);
86 if (it != m_obj_v_m.end()) return it->second;
87 else throw (std::out_of_range(StringUtil::form("%s not found in %s (%s:%d)",
88 name.c_str(), getName().c_str(),
89 __FILE__, __LINE__)));
90}
91
92const DBObjectList& DBObject::getObjects(const std::string& name) const
93{
94 FieldObjectList::const_iterator it = m_obj_v_m.find(name);
95 if (it != m_obj_v_m.end()) return it->second;
96 else throw (std::out_of_range(StringUtil::form("%s not found in %s (%s:%d)",
97 name.c_str(), getName().c_str(),
98 __FILE__, __LINE__)));
99}
100
101DBObject& DBObject::getObject(const std::string& name, int i)
102{
103 FieldObjectList::iterator it = m_obj_v_m.find(name);
104 if (it != m_obj_v_m.end()) return it->second[i];
105 else throw (std::out_of_range(StringUtil::form("%s not found in %s (%s:%d)",
106 name.c_str(), getName().c_str(),
107 __FILE__, __LINE__)));
108}
109
110const DBObject& DBObject::getObject(const std::string& name, int i) const
111{
112 FieldObjectList::const_iterator it = m_obj_v_m.find(name);
113 if (it != m_obj_v_m.end()) return it->second[i];
114 else throw (std::out_of_range(StringUtil::form("%s not found in %s (%s:%d)",
115 name.c_str(), getName().c_str(),
116 __FILE__, __LINE__)));
117}
118
119void DBObject::reset()
120{
121 const DBField::NameList& name_v(getFieldNames());
122 for (size_t ii = 0; ii < name_v.size(); ii++) {
123 const std::string& name(name_v[ii]);
124 if (hasObject(name)) {
125 size_t nobj = getNObjects(name);
126 for (size_t i = 0; i < nobj; i++) getObject(name, i).reset();
127 }
128 }
129 for (FieldValueList::iterator it = m_value_m.begin();
130 it != m_value_m.end(); ++it) {
131 free(it->second);
132 }
133 m_value_m = FieldValueList();
134 m_text_m = FieldTextList();
135 m_obj_v_m = FieldObjectList();
136 AbstractDBObject::reset();
137}
138
139void DBObject::readObject(Reader& reader)
140{
141 reset();
142 setPath(reader.readString());
143 setName(reader.readString());
144 setDate(reader.readInt());
145 int npar = reader.readInt();
146 for (int i = 0; i < npar; i++) {
147 std::string name = reader.readString();
148 DBField::Type type = (DBField::Type)reader.readInt();
149 switch (type) {
150 case DBField::BOOL: addBool(name, reader.readBool()); break;
151 case DBField::CHAR: addChar(name, reader.readChar()); break;
152 case DBField::SHORT: addShort(name, reader.readShort()); break;
153 case DBField::INT: addInt(name, reader.readInt()); break;
154 case DBField::LONG: addLong(name, reader.readLong()); break;
155 case DBField::FLOAT: addFloat(name, reader.readFloat()); break;
156 case DBField::DOUBLE: addDouble(name, reader.readDouble()); break;
157 case DBField::TEXT: addText(name, reader.readString()); break;
158 case DBField::OBJECT: {
159 DBObjectList obj_v;
160 int nobj = reader.readInt();
161 for (int n = 0; n < nobj; n++) {
162 DBObject obj;
163 obj.readObject(reader);
164 obj.setIndex(n);
165 obj_v.push_back(obj);
166 }
167 addObjects(name, obj_v);
168 }; break;
169 default: break;
170 }
171 }
172}
173
174void DBObject::writeObject(Writer& writer) const
175{
176 writer.writeString(getPath());
177 writer.writeString(getName());
178 writer.writeInt(getDate());
179 const DBField::NameList& name_v(getFieldNames());
180 writer.writeInt(name_v.size());
181 for (DBField::NameList::const_iterator iname = name_v.begin();
182 iname != name_v.end(); ++iname) {
183 const std::string name = *iname;
184 DBField::Type type = getProperty(name).getType();
185 writer.writeString(name);
186 writer.writeInt(type);
187 switch (type) {
188 case DBField::BOOL: writer.writeBool(getBool(name)); break;
189 case DBField::CHAR: writer.writeChar(getChar(name)); break;
190 case DBField::SHORT: writer.writeShort(getShort(name)); break;
191 case DBField::INT: writer.writeInt(getInt(name)); break;
192 case DBField::LONG: writer.writeLong(getLong(name)); break;
193 case DBField::FLOAT: writer.writeFloat(getFloat(name)); break;
194 case DBField::DOUBLE: writer.writeDouble(getDouble(name)); break;
195 case DBField::TEXT: writer.writeString(getText(name)); break;
196 case DBField::OBJECT: {
197 const DBObjectList& obj_v(getObjects(name));
198 writer.writeInt(obj_v.size());
199 for (DBObjectList::const_iterator iobj = obj_v.begin();
200 iobj != obj_v.end(); ++iobj) {
201 iobj->writeObject(writer);
202 }
203 }; break;
204 default: break;
205 }
206 }
207}
208
209const void* DBObject::getValue(const std::string& name) const
210{
211 if (!hasValue(name)) return NULL;
212 FieldValueList::const_iterator it = m_value_m.find(name);
213 if (it != m_value_m.end()) return it->second;
214 else throw (std::out_of_range(StringUtil::form("value %s not found", name.c_str())));
215}
216
217const std::string& DBObject::getText(const std::string& name) const
218{
219 if (!hasText(name)) return m_empty;
220 FieldTextList::const_iterator it = m_text_m.find(name);
221 if (it != m_text_m.end()) return it->second;
222 else throw (std::out_of_range(StringUtil::form("text %s not found", name.c_str())));
223}
224
225void DBObject::addValue(const std::string& name, const void* value,
226 DBField::Type type, int)
227{
228 DBField::Property pro(type, 0, 0);
229 int size = pro.getTypeSize();
230 if (size <= 0) return;
231 if (!hasValue(name)) {
232 add(name, pro);
233 void* v = malloc(size);
234 memcpy(v, value, size);
235 m_value_m.insert(FieldValueList::value_type(name, v));
236 } else {
237 memcpy(m_value_m[name], value, size);
238 }
239}
240
241void DBObject::setValue(const std::string& name,
242 const void* value, int)
243{
244 const DBField::Property& pro(getProperty(name));
245 int size = pro.getTypeSize();
246 if (hasField(name) && size > 0) {
247 memcpy(m_value_m[name], value, size);
248 }
249}
250
251void DBObject::addText(const std::string& name,
252 const std::string& value)
253{
254 if (!hasField(name)) {
255 add(name, DBField::Property(DBField::TEXT, 0));
256 m_text_m.insert(FieldTextList::value_type(name, value));
257 } else {
258 m_text_m[name] = value;
259 }
260}
261
262void DBObject::addObject(const std::string& name,
263 const DBObject& obj)
264{
265 if (!hasField(name)) {
266 add(name, DBField::Property(DBField::OBJECT, 0));
267 m_obj_v_m.insert(FieldObjectList::value_type(name, DBObjectList()));
268 }
269 m_obj_v_m[name].push_back(obj);
270 getProperty(name).setLength(m_obj_v_m[name].size());
271}
272
273void DBObject::addObjects(const std::string& name,
274 const DBObjectList& obj_v)
275{
276 if (!hasField(name)) {
277 add(name, DBField::Property(DBField::OBJECT, obj_v.size()));
278 m_obj_v_m.insert(FieldObjectList::value_type(name, obj_v));
279 } else {
280 m_obj_v_m[name] = obj_v;
281 }
282}
283
284void DBObject::print(bool isfull) const
285{
286 const std::string& name_in = "";
287 NameValueList map;
288 search(map, name_in, isfull);
289 size_t length = 0;
290 for (NameValueList::iterator it = map.begin();
291 it != map.end(); ++it) {
292 if (it->name.size() > length) length = it->name.size();
293 }
294 printf("#\n");
295 printf("# DB object (confname = %s) stored at %s\n", getName().c_str(), Date(getDate()).toString());
296 printf("#\n");
297 printf("\n");
298 StringList s = StringUtil::split(getName(), '@');
299 if (s.size() > 1) {
300 printf("%*s : %s\n", int(-length), "nodename", s[0].c_str());
301 printf("%*s : %s\n", int(-length), "config", s[1].c_str());
302 } else {
303 printf("%*s : %s\n", int(-length), "config", getName().c_str());
304 }
305 printf("\n");
306 for (NameValueList::iterator it = map.begin();
307 it != map.end(); ++it) {
308 printf("%*s : %s\n", int(-length), it->name.c_str(), it->value.c_str());
309 }
310 printf("\n");
311 printf("#\n");
312 printf("#\n");
313 printf("#\n");
314}
315
316const std::string DBObject::sprint(bool isfull) const
317{
318 std::stringstream ss;
319 const std::string& name_in = "";
320 NameValueList map;
321 search(map, name_in, isfull);
322 size_t length = 0;
323 for (NameValueList::iterator it = map.begin();
324 it != map.end(); ++it) {
325 if (it->name.size() > length) length = it->name.size();
326 }
327 ss << "#" << std::endl;
328 ss << "# DB object (confname = " << getName() << ")" << std::endl;
329 ss << "#" << std::endl;
330 ss << "" << std::endl;
331 StringList s = StringUtil::split(getName(), '@');
332 if (s.size() > 1) {
333 ss << StringUtil::form("%*s : %s\n", -length, "nodename", s[0].c_str())
334 << std:: endl;
335 ss << StringUtil::form("%*s : %s\n", -length, "config", s[1].c_str())
336 << std:: endl;
337 } else {
338 ss << StringUtil::form("%*s : %s\n", -length, "config", getName().c_str())
339 << std:: endl;
340 }
341 ss << "" << std::endl;
342 for (NameValueList::iterator it = map.begin();
343 it != map.end(); ++it) {
344 ss << StringUtil::form("%*s : %s\n", -length, it->name.c_str(), it->value.c_str())
345 << std::endl;
346 }
347 ss << "" << std::endl;
348 ss << "#" << std::endl;
349 ss << "#" << std::endl;
350 ss << "#" << std::endl;
351 return ss.str();
352}
353
354void DBObject::printHTML(bool isfull) const
355{
356 const std::string& name_in = "";
357 NameValueList map;
358 search(map, name_in, isfull);
359 printf("<table>\n");
360 printf("<caption><strong>%s</strong></caption>\n", getName().c_str());
361 printf("<thead><tr><th>Name</th><th>Value</th>\n</tr></thead>\n");
362 printf("<tbody>\n");
363 StringList s = StringUtil::split(getName(), '@');
364 if (s.size() > 1) {
365 printf("<tr><td>nodename</td><td>%s</td>\n", s[0].c_str());
366 printf("<tr><td>config</td><td>%s</td>\n", s[1].c_str());
367 } else {
368 printf("<tr><td>config</td><td>%s</td>\n", getName().c_str());
369 }
370 std::string rcconfig, dbtable, nodename;
371 for (NameValueList::iterator it = map.begin();
372 it != map.end(); ++it) {
373 if (it->name.find("name") != std::string::npos) {
374 nodename = it->value;
375 printf("<tr><td>%s</td><td>%s</td>\n", it->name.c_str(), it->value.c_str());
376 } else if (it->name.find("rcconfig") != std::string::npos) {
377 rcconfig = it->value;
378 } else if (it->name.find("dbtable") != std::string::npos) {
379 dbtable = it->value;
380 printf("<tr><td>%s</td><td><a href=\"./daqconfig.php?db=%s&config=%s@%s\" >%s/%s</a></td>\n",
381 it->name.c_str(), dbtable.c_str(), nodename.c_str(), rcconfig.c_str(),
382 dbtable.c_str(), rcconfig.c_str());
383 } else {
384 printf("<tr><td>%s</td><td>%s</td>\n", it->name.c_str(), it->value.c_str());
385 }
386 }
387 printf("</tbody>\n");
388 printf("</table>\n");
389}
390
391StringList DBObject::getNameList(bool isfull) const
392{
393 const std::string& name_in = "";
394 NameValueList map;
395 search(map, name_in, isfull);
396 StringList str;
397 for (NameValueList::iterator it = map.begin();
398 it != map.end(); ++it) {
399 str.push_back(it->name);
400 }
401 return str;
402}
403
404void DBObject::search(NameValueList& map, const std::string& name_in, bool isfull)
405const
406{
407 const DBField::NameList& name_v(getFieldNames());
408 for (DBField::NameList::const_iterator it = name_v.begin();
409 it != name_v.end(); ++it) {
410 const std::string& name(*it);
411 const DBField::Property& pro(getProperty(name));
412 std::string name_out = name_in;
413 if (name_in.size() > 0) name_out += ".";
414 name_out += name;
415 std::string ptype;
416 switch (pro.getType()) {
417 case DBField::BOOL: ptype = "bool"; break;
418 case DBField::INT: ptype = "int"; break;
419 case DBField::FLOAT: ptype = "float"; break;
420 case DBField::DOUBLE: ptype = "double"; break;
421 default : break;
422 }
423 if (pro.getType() == DBField::OBJECT) {
424 int length = getNObjects(name);
425 if (!isfull && getObject(name).getPath().size() > 0) {
426 const DBObjectList& objs(getObjects(name));
427 if (length == 1 || objs[1].getPath().size() == 0 || objs[0].getPath() == objs[1].getPath()) {
428 std::string value = objs[0].getPath();
429 value = "object(" + value + ")";
430 NameValue nv;
431 nv.name = name_out.c_str();
432 nv.value = value;
433 nv.type = pro.getType();
434 map.push_back(nv);
435 } else {
436 for (int i = 0; i < length; i++) {
437 std::string value = objs[i].getPath();
438 value = "object(" + value + ")";
439 NameValue nv;
440 nv.name = StringUtil::form("%s[%d].%s", name.c_str(), i, name_out.c_str());
441 nv.value = value;
442 nv.type = pro.getType();
443 map.push_back(nv);
444 }
445 }
446 } else {
447 size_t lengthCur = getNObjects(name);
448 if (lengthCur > 1) {
449 const DBObjectList& objs(getObjects(name));
450 for (size_t i = 0; i < lengthCur; i++) {
451 objs[i].search(map, StringUtil::form("%s[%d]", name_out.c_str(), i), isfull);
452 }
453 } else {
454 const DBObject& obj(getObject(name));
455 obj.search(map, name_out, isfull);
456 }
457 }
458 } else {
459 std::string value = getValueText(name);
460 if (ptype.size() > 0) value = ptype + "(" + value + ")";
461 NameValue nv;
462 nv.name = name_out;
463 nv.value = value;
464 nv.type = pro.getType();
465 if (pro.getType() != DBField::TEXT) {
466 nv.buf = (void*)getValue(name);
467 } else {
468 nv.buf = (void*)&getText(name);
469 }
470 map.push_back(nv);
471 }
472 }
473}
474
475const std::string DBObject::printSQL(const std::string& table, int id) const
476{
477 std::stringstream ss;
478
479 const std::string& name_in = "";
480 NameValueList map;
481 bool isfull = false;
482 search(map, name_in, isfull);
483 for (NameValueList::iterator it = map.begin();
484 it != map.end(); ++it) {
485 NameValue& nv(*it);
486 std::string value = nv.value;
487 std::string::size_type pos = value.find_first_of("(");
488 DBField::Type type = DBField::TEXT;
489 if (pos != std::string::npos) {
490 std::string type_s = value.substr(0, pos);
491 if (type_s == "bool") type = DBField::BOOL;
492 else if (type_s == "char") type = DBField::CHAR;
493 else if (type_s == "short") type = DBField::SHORT;
494 else if (type_s == "int") type = DBField::INT;
495 else if (type_s == "float") type = DBField::FLOAT;
496 else if (type_s == "double") type = DBField::DOUBLE;
497 else if (type_s == "object") type = DBField::OBJECT;
498 if (type != DBField::TEXT) {
499 value = StringUtil::replace(value.substr(pos + 1), ")", "");
500 }
501 }
502
503 switch (nv.type) {
504 case DBField::BOOL:
505 ss << "insert into " << table << " (pid,name,value_b) values "
506 << "(" << id << ",'" << nv.name << "'," << value << ");" << std::endl;
507 break;
508 case DBField::INT:
509 ss << "insert into " << table << " (pid,name,value_i) values "
510 << "(" << id << ",'" << nv.name << "'," << value << ");" << std::endl;
511 break;
512 case DBField::FLOAT:
513 case DBField::DOUBLE:
514 ss << "insert into " << table << " (pid,name,value_f) values "
515 << "(" << id << ",'" << nv.name << "'," << value << ");" << std::endl;
516 break;
517 case DBField::TEXT:
518 ss << "insert into " << table << " (pid,name,value_t) values "
519 << "(" << id << ",'" << nv.name << "','" << value << "');" << std::endl;
520 break;
521 default : break;
522 }
523 }
524 return ss.str();
525}
526
Abstract base class for different kinds of events.