LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
DBFolder.cxx
Go to the documentation of this file.
1 #include "DBFolder.h"
2 #include "WebDBIConstants.h"
3 #include "WebError.h"
5 
6 #include "cetlib/search_path.h"
7 #include "cetlib_except/exception.h"
9 #include "sqlite3.h"
10 #include "wda.h"
11 #include <cstring>
12 #include <sstream>
13 #include <stdlib.h>
14 
15 namespace lariov {
16 
17  // Constructor.
18 
19  DBFolder::DBFolder(const std::string& name,
20  const std::string& url,
21  const std::string& url2,
22  const std::string& tag,
23  bool usesqlite,
24  bool testmode)
25  {
26  fFolderName = name;
27  fURL = url;
28  fURL2 = url2;
29  fTag = tag;
30  fUseSQLite = usesqlite;
31  fTestMode = testmode;
32  if (fURL[fURL.length() - 1] == '/') { fURL = fURL.substr(0, fURL.length() - 1); }
33 
34  fCachedRowNumber = -1;
35  fCachedChannel = 0;
36 
37  fMaximumTimeout = 4 * 60; //4 minutes
38 
39  // If UsqSQLite is true, hunt for sqlite database file.
40  // It is an error if this file can't be found.
41 
42  //mf::LogInfo("DBFolder") << "DBFolder: Folder name = " << fFolderName << "\n";
43  if (fUseSQLite) {
44  std::string dbname = fFolderName + ".db";
45  cet::search_path sp("FW_SEARCH_PATH");
46  fSQLitePath = sp.find_file(dbname); // Throws exception if not found.
47  //mf::LogInfo("DBFolder") << "DBFolder: SQLite database path = " << fSQLitePath << "\n";
48  }
49  //else
50  // mf::LogInfo("DBFolder") << "DBFolder: database url = " << fURL << "\n";
51 
52  if (fTestMode && fURL2 != "") {
53  mf::LogInfo log("DBFolder");
54  log << "\nDBFolder test mode, will compare the following urls data."
55  << "\n";
56  log << fURL << "\n";
57  log << fURL2 << "\n"
58  << "\n";
59  }
60  if (fTestMode && fUseSQLite) {
61  mf::LogInfo log("DBFolder");
62  log << "\nDBFolder test mode, will compare the following url and sqlite data."
63  << "\n";
64  log << fURL << "\n";
65  log << fSQLitePath << "\n"
66  << "\n";
67  }
68  }
69 
70  // Destructor.
71 
73 
74  // Data accessors.
75 
76  int DBFolder::GetNamedChannelData(DBChannelID_t channel, const std::string& name, bool& data)
77  {
78 
79  int err = 0;
80 
81  // Make sure cached row is valid.
82 
83  GetRow(channel);
84 
85  // Get column index.
86 
87  size_t col = GetColumn(name);
88 
89  // Get value.
90 
91  long value = fCachedRow.getLongData(col);
92  data = (value != 0);
93 
94  return err;
95  }
96 
97  int DBFolder::GetNamedChannelData(DBChannelID_t channel, const std::string& name, long& data)
98  {
99 
100  int err = 0;
101 
102  // Make sure cached row is valid.
103 
104  GetRow(channel);
105 
106  // Get column index.
107 
108  size_t col = GetColumn(name);
109 
110  // Get value.
111 
112  data = fCachedRow.getLongData(col);
113 
114  // Done.
115 
116  return err;
117  }
118 
119  int DBFolder::GetNamedChannelData(DBChannelID_t channel, const std::string& name, double& data)
120  {
121 
122  int err = 0;
123 
124  // Make sure cached row is valid.
125 
126  GetRow(channel);
127 
128  // Get column index.
129 
130  size_t col = GetColumn(name);
131 
132  // Get value.
133 
134  data = fCachedRow.getDoubleData(col);
135 
136  // Done.
137 
138  return err;
139  }
140 
141  int DBFolder::GetNamedChannelData(DBChannelID_t channel,
142  const std::string& name,
143  std::string& data)
144  {
145 
146  int err = 0;
147 
148  // Make sure cached row is valid.
149 
150  GetRow(channel);
151 
152  // Get column index.
153 
154  size_t col = GetColumn(name);
155 
156  // Get value.
157 
158  data = fCachedRow.getStringData(col);
159 
160  // Done.
161 
162  return err;
163  }
164 
165  // Not sure why the following accessor is included. Doesn't seem to be used.
166 
167  /*
168  int DBFolder::GetNamedChannelData(DBChannelID_t channel, const std::string& name, std::vector<double>& data) {
169 
170  data.clear();
171 
172  Tuple tup;
173  size_t col = this->GetRow(channel, name, tup);
174  int err=0;
175  double buf[kBUFFER_SIZE];
176 
177  DataRec *dataRec = (DataRec *)tup;
178  // for c2: col is an unsigned int and cannot be less than 0
179  // if (col < 0 || col >= dataRec->ncolumns) {
180  if (col >= dataRec->ncolumns) {
181  err=-1;
182  return err;
183  }
184 
185  char* sptr = dataRec->columns[col];
186  if ( *sptr == '[') sptr +=1; //expect an initial bracket and skip it
187  else {
188  err=-2;
189  return err;
190  }
191 
192  char* eptr;
193  double val;
194  unsigned int array_size=0;
195  for (unsigned int i=0; i < kBUFFER_SIZE; ++i) {
196  val = strtod(sptr, &eptr); //Try to convert
197  if (sptr==eptr) break; //conversion failed
198  if (*sptr=='\0') break; //end loop if buffer ends
199 
200  buf[array_size++] = val;
201 
202  if ( *eptr == ']') break; //found the closing bracket, we're done
203  else sptr = eptr+1; //point to the next value
204  }
205 
206  data.insert(data.begin(), buf, buf + array_size);
207  releaseTuple(tup);
208  return err;
209  }
210  */
211 
212  int DBFolder::GetChannelList(std::vector<DBChannelID_t>& channels) const
213  {
214 
215  channels = fCache.channels();
216  return 0;
217  }
218 
219  // Update cached row.
220 
221  void DBFolder::GetRow(DBChannelID_t channel)
222  {
223 
224  // Check if we need to update the cached row.
225 
226  if (fCachedChannel != channel || !fCachedRow.isValid() ||
227  fCachedRow.getLongData(0) != channel) {
228 
229  // Update cached row number (binary serach).
230 
231  int row = fCache.getRowNumber(channel);
232 
233  // Throw an exception if we didn't find a matching role.
234 
235  if (row < 0) {
236  std::string msg = "Channel " + std::to_string(channel) + " is not found in database!";
237  throw WebError(msg);
238  }
239 
240  // Update cached row.
241 
242  fCachedRowNumber = row;
243  fCachedChannel = channel;
244  fCachedRow = fCache.getRow(row);
245  }
246  }
247 
248  // Find matching column.
249 
250  size_t DBFolder::GetColumn(const std::string& name) const
251  {
252  int col = fCache.getColNumber(name);
253 
254  // See if we found a matching column.
255 
256  if (col < 0) {
257  std::string msg = "Column " + name + " is not found in database!";
258  throw WebError(msg);
259  }
260 
261  // Done.
262 
263  return col;
264  }
265 
266  //returns true if an Update is performed, false if not
267  bool DBFolder::UpdateData(DBTimeStamp_t raw_time)
268  {
269 
270  //convert to IOVTimeStamp
272 
273  //check if cache is updated
274  if (IsValid(ts)) return false;
275 
276  //release cached data.
277  fCache = DBDataset();
279  fCachedRowNumber = -1;
280  fCachedChannel = 0;
281 
282  //get full url string
283  std::stringstream fullurl;
284  fullurl << fURL << "/data?f=" << fFolderName << "&t=" << ts.DBStamp();
285  if (fTag.length() > 0) fullurl << "&tag=" << fTag;
286 
287  //mf::LogInfo log("DBFolder")
288  //log << "In DBFolder::UpdateData" << "\n";
289  //log << "t=" << raw_time/1000000000 << "\n";
290  //log << "Full url = " << fullurl.str() << "\n";
291 
292  //get new dataset
293  if (fSQLitePath != "" && !fTestMode) { GetSQLiteData(raw_time / 1000000000, fCache); }
294  else {
295  if (fTestMode) {
296  mf::LogInfo log("DBFolder");
297  log << "Accessing primary calibration data from http conditions database server."
298  << "\n";
299  log << "Folder = " << fFolderName << "\n";
300  }
301  int err = 0;
302  Dataset data = getDataWithTimeout(fullurl.str().c_str(), NULL, fMaximumTimeout, &err);
303  int status = getHTTPstatus(data);
304  if (status != 200) {
305  std::string msg = "HTTP error from " + fullurl.str() +
306  ": status: " + std::to_string(status) + ": " +
307  std::string(getHTTPmessage(data));
308  throw WebError(msg);
309  }
310  fCache = DBDataset(data, true);
311  }
312  //DumpDataset(fCache);
313 
314  // If test mode is selected, get comparison data.
315 
316  if (fTestMode) {
317  if (fSQLitePath != "") {
318  DBDataset compare1;
319  mf::LogInfo("DBFolder") << "Accessing comparison data from sqlite database " << fSQLitePath
320  << "\n";
321  GetSQLiteData(raw_time / 1000000000, compare1);
322  CompareDataset(fCache, compare1);
323  }
324  if (fURL2 != "") {
325  mf::LogInfo("DBFolder") << "Accessing comparison data from second database url."
326  << "\n";
327  std::stringstream fullurl2;
328  fullurl2 << fURL2 << "/data?f=" << fFolderName << "&t=" << ts.DBStamp();
329  if (fTag.length() > 0) fullurl2 << "&tag=" << fTag;
330  mf::LogInfo("DBFolder") << "Full url = " << fullurl2.str() << "\n";
331  int err = 0;
332  Dataset data = getDataWithTimeout(fullurl2.str().c_str(), NULL, fMaximumTimeout, &err);
333  int status = getHTTPstatus(data);
334  if (status != 200) {
335  std::string msg = "HTTP error from " + fullurl2.str() +
336  ": status: " + std::to_string(status) + ": " +
337  std::string(getHTTPmessage(data));
338  throw WebError(msg);
339  }
340  DBDataset compare2(data, true);
341  CompareDataset(fCache, compare2);
342  }
343  }
344  return true;
345  }
346 
347  // Query data from sqlite database.
348  // The return value of type Dataset (aka void*), is partially opaque type HttpResponse*
349  // (defined in wda.c and copied above).
350 
351  void DBFolder::GetSQLiteData(int t, DBDataset& data) const
352  {
353  if (fSQLitePath == "") return;
354 
355  // DBDataset data to be filled.
356 
357  IOVTimeStamp begin_ts(0, 0); // IOV begin time.
358  IOVTimeStamp end_ts(0, 0); // IOV end time.
359  std::vector<std::string> column_names; // Column names.
360  std::vector<std::string> column_types; // Column types.
361  std::vector<DBChannelID_t> channels; // Channels.
362  std::vector<DBDataset::value_type> values; // Calibration data (length nchan*ncols).
363 
364  //mf::LogInfo log("DBFolder")
365  //log << "DBFolder::GetSQLiteData" << "\n";
366  //log << "t=" << t << "\n";
367  //log << "sqlite path = " << fSQLitePath << "\n";
368 
369  // Open sqlite database.
370 
371  //mf::LogInfo("DBFolder") << "Opening sqlite database " << fSQLitePath << "\n";
372  sqlite3* db;
373  int rc = sqlite3_open(fSQLitePath.c_str(), &db);
374  if (rc != SQLITE_OK) {
375  mf::LogError("DBFolder") << "Failed to open sqlite database " << fSQLitePath << "\n";
376  throw cet::exception("DBFolder") << "Failed to open sqlite database " << fSQLitePath;
377  }
378 
379  // Query begin time of IOV.
380 
381  std::string table_iovs = fFolderName + "_iovs";
382  std::string table_tag_iovs = fFolderName + "_tag_iovs";
383  std::ostringstream sql;
384  sql << "SELECT " << table_iovs << ".iov_id," << table_iovs << ".begin_time"
385  << " FROM " << table_tag_iovs << "," << table_iovs << " WHERE " << table_tag_iovs
386  << ".tag='" << fTag << "'"
387  << " AND " << table_tag_iovs << ".iov_id=" << table_iovs << ".iov_id"
388  << " AND " << table_iovs << ".begin_time <= " << t << " ORDER BY " << table_iovs
389  << ".begin_time desc";
390  //mf::LogInfo("DBFolder") << "sql = " << sql.str() << "\n";
391 
392  // Prepare query.
393 
394  sqlite3_stmt* stmt;
395  rc = sqlite3_prepare_v2(db, sql.str().c_str(), -1, &stmt, 0);
396  if (rc != SQLITE_OK) {
397  mf::LogError log("DBFolder");
398  log << "sqlite3_prepare_v2 failed." << fSQLitePath << "\n";
399  log << "Failed sql = " << sql.str() << "\n";
400  throw cet::exception("DBFolder") << "sqlite3_prepare_v2 error.";
401  }
402 
403  // Execute query.
404  // Just retrieve first row.
405  // It is an error if we don't get at least one row.
406 
407  rc = sqlite3_step(stmt);
408  //int iov_id = 0;
409  int begin_time = 0;
410  if (rc == SQLITE_ROW) {
411  //iov_id = sqlite3_column_int(stmt, 0);
412  begin_time = sqlite3_column_int(stmt, 1);
413  //mf::LogInfo log("DBFolder")
414  //log << "iov_id = " << iov_id << "\n";
415  //log << "begin_time = " << begin_time << "\n";
416  }
417  else {
418  mf::LogError("DBFolder") << "sqlite3_step returned error result = " << rc << "\n";
419  throw cet::exception("DBFolder") << "sqlite3_step error.";
420  }
421 
422  // Delete query.
423 
424  sqlite3_finalize(stmt);
425 
426  // Query end time of IOV.
427 
428  sql.str("");
429  sql << "SELECT " << table_iovs << ".begin_time"
430  << " FROM " << table_tag_iovs << "," << table_iovs << " WHERE " << table_tag_iovs
431  << ".tag='" << fTag << "'"
432  << " AND " << table_tag_iovs << ".iov_id=" << table_iovs << ".iov_id"
433  << " AND " << table_iovs << ".begin_time > " << t << " ORDER BY " << table_iovs
434  << ".begin_time";
435  //mf::LogInfo("DBFolder") << "sql = " << sql.str() << "\n";
436 
437  // Prepare query.
438 
439  rc = sqlite3_prepare_v2(db, sql.str().c_str(), -1, &stmt, 0);
440  if (rc != SQLITE_OK) {
441  mf::LogError log("DBFolder");
442  log << "sqlite3_prepare_v2 failed." << fSQLitePath << "\n";
443  log << "Failed sql = " << sql.str() << "\n";
444  throw cet::exception("DBFolder") << "sqlite3_prepare_v2 error.";
445  }
446 
447  // Execute query.
448  // Just retrieve first row.
449  // If we don't get any rows, then end time is infinite.
450 
451  rc = sqlite3_step(stmt);
452  int end_time = 0;
453  if (rc == SQLITE_ROW) {
454  end_time = sqlite3_column_int(stmt, 0);
455  //mf::LogInfo("DBFolder") << "end_time = " << end_time << "\n";
456  }
457  else if (rc != SQLITE_DONE) {
458  mf::LogError("DBFolder") << "sqlite3_step returned error result = " << rc << "\n";
459  throw cet::exception("DBFolder") << "sqlite3_step error.";
460  }
461 
462  // Delete query.
463 
464  sqlite3_finalize(stmt);
465 
466  // Query count of channels.
467  // We do this so that we know how much memory to allocate.
468 
469  std::string table_data = fFolderName + "_data";
470  sql.str("");
471  sql << "SELECT COUNT(DISTINCT channel)"
472  << " FROM " << table_data << "," << table_iovs << "," << table_tag_iovs << " WHERE "
473  << table_tag_iovs << ".tag='" << fTag << "'"
474  << " AND " << table_iovs << ".iov_id=" << table_tag_iovs << ".iov_id"
475  << " AND " << table_data << ".__iov_id=" << table_tag_iovs << ".iov_id"
476  << " AND " << table_iovs << ".begin_time <= " << t;
477  //mf::LogInfo("DBFolder") << "sql = " << sql.str() << "\n";
478 
479  // Prepare query.
480 
481  rc = sqlite3_prepare_v2(db, sql.str().c_str(), -1, &stmt, 0);
482  if (rc != SQLITE_OK) {
483  mf::LogError log("DBFolder");
484  log << "sqlite3_prepare_v2 failed." << fSQLitePath << "\n";
485  log << "Failed sql = " << sql.str() << "\n";
486  throw cet::exception("DBFolder") << "sqlite3_prepare_v2 error.";
487  }
488 
489  // Execute query.
490  // Retrieve one row.
491  // It is an error if we don't get at least one row.
492 
493  rc = sqlite3_step(stmt);
494  unsigned int nrows = 0;
495  if (rc == SQLITE_ROW) {
496  nrows = sqlite3_column_int(stmt, 0);
497  //mf::LogInfo("DBFolder") << "Number of data rows = " << nrows << "\n";
498  }
499  else {
500  mf::LogError("DBFolder") << "sqlite3_step returned error result = " << rc << "\n";
501  throw cet::exception("DBFolder") << "sqlite3_step error.";
502  }
503 
504  // Reserve collections that depend on number of rows (only).
505 
506  channels.reserve(nrows);
507 
508  // Delete query.
509 
510  sqlite3_finalize(stmt);
511 
512  // Stash begin time.
513 
514  begin_ts = IOVTimeStamp(begin_time, 0);
515 
516  // Stash end time.
517 
518  if (end_time == 0)
519  end_ts = IOVTimeStamp::MaxTimeStamp();
520  else
521  end_ts = IOVTimeStamp(end_time, 0);
522 
523  // Main data query.
524 
525  sql.str("");
526  sql << "SELECT " << table_data << ".*,MAX(begin_time)"
527  << " FROM " << table_data << "," << table_iovs << "," << table_tag_iovs << " WHERE "
528  << table_tag_iovs << ".tag='" << fTag << "'"
529  << " AND " << table_iovs << ".iov_id=" << table_tag_iovs << ".iov_id"
530  << " AND " << table_data << ".__iov_id=" << table_tag_iovs << ".iov_id"
531  << " AND " << table_iovs << ".begin_time <= " << t << " GROUP BY channel"
532  << " ORDER BY channel";
533  //mf::LogInfo("DBFolder") << "sql = " << sql.str() << "\n";
534 
535  // Prepare query.
536 
537  rc = sqlite3_prepare_v2(db, sql.str().c_str(), -1, &stmt, 0);
538  if (rc != SQLITE_OK) {
539  mf::LogError log("DBFolder");
540  log << "sqlite3_prepare_v2 failed." << fSQLitePath << "\n";
541  log << "Failed sql = " << sql.str() << "\n";
542  throw cet::exception("DBFolder") << "sqlite3_prepare_v2 error.";
543  }
544 
545  // Execute the query and retrieve one row.
546  // We do this to extract the number, names, and types of relevant columns.
547 
548  int ncols = sqlite3_column_count(stmt);
549  column_names.reserve(ncols);
550  column_types.reserve(ncols);
551 
552  rc = sqlite3_step(stmt);
553  if (rc == SQLITE_ROW) {
554 
555  // Loop over columns.
556 
557  for (int col = 0; col < ncols; ++col) {
558  std::string colname = sqlite3_column_name(stmt, col);
559 
560  // Ignore columns that begin with "_".
561  // Also ignore utility column MAX(begin_time).
562 
563  if (colname[0] != '_' && colname.substr(0, 3) != "MAX") {
564  column_names.push_back(colname);
565  int dtype = sqlite3_column_type(stmt, col);
566  if (dtype == SQLITE_INTEGER)
567  column_types.push_back("integer");
568  else if (dtype == SQLITE_FLOAT)
569  column_types.push_back("real");
570  else if (dtype == SQLITE_TEXT)
571  column_types.push_back("text");
572  else if (dtype == SQLITE_NULL)
573  column_types.push_back("NULL");
574  else {
575  mf::LogError("DBFolder") << "Unknown type " << dtype << "\n";
576  throw cet::exception("DBFolder") << "Unknown type " << dtype;
577  }
578  //mf::LogInfo("DBFolder") << "Column " << col
579  // << ", name=" << column_names.back()
580  // << ", type=" << column_types.back() << "\n";
581  }
582  }
583  }
584  else {
585  mf::LogError("DBFolder") << "No data rows."
586  << "\n";
587  throw cet::exception("DBFolder") << "No data rows.";
588  }
589 
590  // Remember the number of relevant columns.
591 
592  size_t nrelcols = column_names.size();
593  values.reserve(nrows * nrelcols);
594 
595  // Re-execute query.
596  // Retrieve all data rows and stash in result.
597 
598  rc = sqlite3_reset(stmt);
599  if (rc != SQLITE_OK) {
600  mf::LogError("DBFolder") << "sqlite3_reset failed."
601  << "\n";
602  throw cet::exception("DBFolder") << "sqlite3_failed.";
603  }
604  size_t irow = 0;
605  while (rc != SQLITE_DONE) {
606  rc = sqlite3_step(stmt);
607  if (rc == SQLITE_ROW) {
608  ++irow;
609  //mf::LogInfo("DBFolder") << irow << " rows." << "\n";
610  if (irow > nrows) {
611  mf::LogError("DBFolder") << "Too many data rows " << irow << "\n";
612  throw cet::exception("DBFolder") << "Too many data rows " << irow;
613  }
614 
615  // Loop over columns.
616  // Remember that ncols is the number of columns returned by the query,
617  // not the number of columns that get stored (some columns are ignored).
618 
619  bool firstcol = true;
620  for (int col = 0; col < ncols; ++col) {
621  std::string colname = sqlite3_column_name(stmt, col);
622 
623  // Ignore columns that begin with "_".
624  // Also ignore utility column MAX(begin_time).
625 
626  if (colname[0] != '_' && colname.substr(0, 3) != "MAX") {
627  int dtype = sqlite3_column_type(stmt, col);
628 
629  if (dtype == SQLITE_INTEGER) {
630  long value = sqlite3_column_int(stmt, col);
631  //mf::LogInfo("DBFolder") << "Value = " << value << "\n";
632  values.push_back(DBDataset::value_type(value));
633  if (firstcol) channels.push_back(value);
634  }
635  else if (dtype == SQLITE_FLOAT) {
636  double value = sqlite3_column_double(stmt, col);
637  //mf::LogInfo("DBFolder") << "Value = " << value << "\n";
638  values.push_back(DBDataset::value_type(value));
639  if (firstcol) {
640  mf::LogError("DBFolder") << "First column has wrong type float."
641  << "\n";
642  throw cet::exception("DBFolder") << "First column has wrong type float.";
643  }
644  }
645  else if (dtype == SQLITE_TEXT) {
646  const char* s = (const char*)sqlite3_column_text(stmt, col);
647  //mf::LogInfo("DBFolder") << "Value = " << s << "\n";
648  values.emplace_back(std::make_unique<std::string>(s));
649  if (firstcol) {
650  mf::LogError("DBFolder") << "First column has wrong type text."
651  << "\n";
652  throw cet::exception("DBFolder") << "First column has wrong type text.";
653  }
654  }
655  else if (dtype == SQLITE_NULL) {
656  values.push_back(DBDataset::value_type());
657  //mf::LogInfo("DBFolder") << "Value = NULL" << "\n";
658  if (firstcol) {
659  mf::LogError("DBFolder") << "First column has wrong type null."
660  << "\n";
661  throw cet::exception("DBFolder") << "First column has wrong type null.";
662  }
663  }
664  else {
665  mf::LogError("DBFolder") << "Unrecognized sqlite data type"
666  << "\n";
667  throw cet::exception("DBFolder") << "Unrecognized sqlite data type.";
668  }
669  firstcol = false;
670  }
671  }
672  }
673  else if (rc != SQLITE_DONE) {
674  mf::LogError("DBFolder") << "sqlite3_step returned error result = " << rc << "\n";
675  throw cet::exception("DBFolder") << "sqlite3_step error.";
676  }
677  }
678  if (irow != nrows) {
679  mf::LogError("DBFolder") << "Wrong number of data rows " << irow << "," << nrows << "\n";
680  throw cet::exception("DBFolder")
681  << "Wrong number of data rows " << irow << "," << nrows << "\n";
682  }
683  if (values.size() != nrows * nrelcols) {
684  mf::LogError("DBFolder") << "Wrong number of values " << values.size() << "," << nrows << ","
685  << nrelcols << "\n";
686  throw cet::exception("DBFolder")
687  << "Wrong number of values " << values.size() << "," << nrows << "," << nrelcols << "\n";
688  }
689 
690  // Delete statement.
691 
692  sqlite3_finalize(stmt);
693 
694  // Close database.
695 
696  sqlite3_close(db);
697 
698  // Fill result.
699 
700  data = DBDataset(begin_ts,
701  end_ts,
702  std::move(column_names),
703  std::move(column_types),
704  std::move(channels),
705  std::move(values));
706 
707  // Done.
708 
709  return;
710  }
711 
712  // Dump dataset by rows.
713 
714  void DBFolder::DumpDataset(const DBDataset& data) const
715  {
716  size_t nrows = data.nrows();
717  size_t ncols = data.ncols();
718  mf::LogInfo log("DBFolder");
719  log << "Dataset contains " << nrows << " rows and " << ncols << " columns."
720  << "\n";
721 
722  // Begin time.
723 
724  log << "IOV start time = " << data.beginTime().DBStamp() << "\n";
725 
726  // End time.
727 
728  log << "IOV end time = " << data.endTime().DBStamp() << "\n";
729 
730  // Columnn names.
731 
732  const std::vector<std::string>& names = data.colNames();
733  for (size_t c = 0; c < ncols; ++c)
734  log << "Column " << c << ", name = " << names[c] << "\n";
735 
736  // Row 3 - column types.
737 
738  const std::vector<std::string>& types = data.colTypes();
739  for (size_t c = 0; c < ncols; ++c)
740  log << "Column " << c << ", type = " << types[c] << "\n";
741 
742  // Data rows.
743 
744  for (size_t row = 0; row < nrows; ++row) {
745  log << "\nRow " << row << "\n";
746  DBDataset::DBRow dbrow = data.getRow(row);
747 
748  // Loop over columns.
749 
750  for (size_t col = 0; col < ncols; ++col) {
751  if (types[col] == "bigint" || types[col] == "integer" || types[col] == "boolean") {
752  long value = dbrow.getLongData(col);
753  log << names[col] << " = " << value << "\n";
754  }
755  else if (types[col] == "real") {
756  double value = dbrow.getDoubleData(col);
757  log << names[col] << " = " << value << "\n";
758  }
759  else if (types[col] == "text" or types[col] == "boolean") {
760  std::string value = dbrow.getStringData(col);
761  log << names[col] << " = " << value << "\n";
762  }
763  else {
764  mf::LogError("DBFolder") << "Unknown type " << types[col] << "\n";
765  throw cet::exception("DBFolder") << "Unknown type.";
766  }
767  }
768  }
769  }
770 
771  bool DBFolder::CompareDataset(const DBDataset& data1, const DBDataset& data2) const
772  {
773  bool compare_ok = true;
774  mf::LogInfo("DBFolder") << "\nComparing datasets."
775  << "\n";
776 
777  size_t nrows1 = data1.nrows();
778  size_t nrows2 = data2.nrows();
779  //mf::LogInfo log("DBFolder");
780  //log << "Dataset 1 contains " << nrows1 << " rows." << "\n";
781  //log << "Dataset 2 contains " << nrows2 << " rows." << "\n";
782  if (nrows1 != nrows2) compare_ok = false;
783 
784  // Compare begin time.
785 
786  std::string begin1 = data1.beginTime().DBStamp();
787  std::string begin2 = data2.beginTime().DBStamp();
788  if (begin1 != begin2) compare_ok = false;
789 
790  // Compare end time.
791 
792  std::string end1 = data1.beginTime().DBStamp();
793  std::string end2 = data2.beginTime().DBStamp();
794  if (end1 != end2) compare_ok = false;
795 
796  // Compare column names.
797 
798  size_t ncols1 = data1.ncols();
799  size_t ncols2 = data2.ncols();
800  const std::vector<std::string>& names1 = data1.colNames();
801  const std::vector<std::string>& names2 = data2.colNames();
802  if (ncols1 != ncols2 || ncols1 != names1.size() || ncols2 != names2.size()) {
803  mf::LogWarning("DBFolder") << "Columns names size mismatch " << ncols1 << " vs. " << ncols2
804  << " vs. " << names1.size() << " vs. " << names2.size() << "\n";
805  compare_ok = false;
806  }
807  if (compare_ok) {
808  for (size_t c = 0; c < ncols1; ++c) {
809  if (names1[c] != names2[c]) {
810  mf::LogWarning("DBFolder")
811  << "Name mismatch " << names1[c] << " vs. " << names2[c] << "\n";
812  compare_ok = false;
813  }
814  }
815  }
816 
817  // Compare column types.
818 
819  const std::vector<std::string>& types1 = data1.colTypes();
820  const std::vector<std::string>& types2 = data2.colTypes();
821  if (ncols1 != ncols2 || ncols1 != types1.size() || ncols2 != types2.size()) {
822  mf::LogWarning("DBFolder") << "Column types ize mismatch " << ncols1 << " vs. " << ncols2
823  << " vs. " << types1.size() << " vs. " << types2.size() << "\n";
824  compare_ok = false;
825  }
826  if (compare_ok) {
827  for (size_t c = 0; c < ncols2; ++c) {
828 
829  // Type "bigint" matches "integer."
830  // Type "boolean" matches "integer."
831 
832  std::string type1 = types1[c];
833  std::string type2 = types2[c];
834  if (type1 == "bigint" || type1 == "boolean") type1 = "integer";
835  if (type2 == "bigint" || type2 == "boolean") type2 = "integer";
836  if (type1 != type2) {
837  mf::LogWarning("DBFolder") << "Type mismatch " << type1 << " vs. " << type2 << "\n";
838  compare_ok = false;
839  }
840  }
841  }
842 
843  // Compare channels.
844 
845  const std::vector<DBChannelID_t>& channels1 = data1.channels();
846  const std::vector<DBChannelID_t>& channels2 = data2.channels();
847  if (nrows1 != nrows2 || nrows1 != channels1.size() || nrows2 != channels2.size()) {
848  mf::LogWarning("DBFolder") << "Channels size mismatch " << nrows1 << " vs. " << nrows2
849  << " vs. " << channels1.size() << " vs. " << channels2.size()
850  << "\n";
851  compare_ok = false;
852  }
853  if (compare_ok) {
854  for (size_t r = 0; r < nrows1; ++r) {
855  if (channels1[r] != channels2[r]) {
856  mf::LogWarning("DBFolder")
857  << "Channel mismatch " << channels1[r] << " vs. " << channels2[r] << "\n";
858  compare_ok = false;
859  }
860  }
861  }
862 
863  // Compare number of values.
864 
865  if (data1.data().size() != data2.data().size()) {
866  mf::LogWarning("DBFolder") << "Values size mismatch " << data1.data().size() << " vs. "
867  << data2.data().size() << "\n";
868  compare_ok = false;
869  }
870 
871  // Data rows.
872  if (compare_ok) {
873  for (size_t row = 0; row < nrows1; ++row) {
874 
875  DBDataset::DBRow dbrow1 = data1.getRow(row);
876  DBDataset::DBRow dbrow2 = data2.getRow(row);
877  //mf::LogInfo("DBFolder") << "\nRow " << row << "\n";
878 
879  // Loop over columns.
880 
881  for (size_t col = 0; col < ncols1; ++col) {
882  if (types1[col] == "integer" || types1[col] == "bigint" || types1[col] == "boolean") {
883  long value1 = dbrow1.getLongData(col);
884  long value2 = dbrow2.getLongData(col);
885  //mf::LogInfo log("DBFolder")
886  //log << names1[col] << " 1 = " << value1 << "\n";
887  //log << names2[col] << " 2 = " << value2 << "\n";
888  if (value1 != value2) {
889  mf::LogWarning("DBFolder")
890  << "Value mismatch " << value1 << " vs. " << value2 << "\n";
891  compare_ok = false;
892  }
893  }
894  else if (types1[col] == "real") {
895  double value1 = dbrow1.getDoubleData(col);
896  double value2 = dbrow2.getDoubleData(col);
897  //mf::LogInfo log("DBFolder")
898  //log << names1[col] << " 1 = " << value1 << "\n";
899  //log << names2[col] << " 2 = " << value2 << "\n";
900  if (value1 != value2) {
901  mf::LogWarning("DBFolder")
902  << "Value mismatch " << value1 << " vs. " << value2 << "\n";
903  compare_ok = false;
904  }
905  }
906  else if (types1[col] == "text") {
907  std::string value1 = dbrow2.getStringData(col);
908  std::string value2 = dbrow2.getStringData(col);
909  if (value1 != value2) {
910  mf::LogWarning("DBFolder")
911  << "Value mismatch " << value1 << " vs. " << value2 << "\n";
912  compare_ok = false;
913  }
914  }
915  else {
916  mf::LogError("DBFolder") << "Unknown type " << types1[col] << "\n";
917  throw cet::exception("DBFolder") << "Unknown type.";
918  }
919  }
920  }
921  }
922 
923  if (compare_ok) {
924  mf::LogInfo("DBFolder") << "Comparison OK.\n"
925  << "\n";
926  }
927  else {
928  mf::LogError("DBFolder") << "Comparison fail."
929  << "\n";
930  throw cet::exception("DBFolder") << "Comparison fail.";
931  }
932  return compare_ok;
933  }
934 
935 } //end namespace lariov
TRandom r
Definition: spectrum.C:23
std::string fURL
Definition: DBFolder.h:61
std::variant< long, double, std::unique_ptr< std::string > > value_type
Definition: DBDataset.h:64
virtual ~DBFolder()
Definition: DBFolder.cxx:72
int GetNamedChannelData(DBChannelID_t channel, const std::string &name, bool &data)
Definition: DBFolder.cxx:76
DBDataset fCache
Definition: DBFolder.h:72
int fCachedRowNumber
Definition: DBFolder.h:76
double getDoubleData(size_t col) const
Definition: DBDataset.h:84
bool UpdateData(DBTimeStamp_t raw_time)
Definition: DBFolder.cxx:267
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
void GetRow(DBChannelID_t channel)
Definition: DBFolder.cxx:221
size_t nrows() const
Definition: DBDataset.h:117
const std::vector< std::string > & colNames() const
Definition: DBDataset.h:119
DBDataset::DBRow fCachedRow
Definition: DBFolder.h:78
const std::string & DBStamp() const
Definition: IOVTimeStamp.h:39
const std::string & getStringData(size_t col) const
Definition: DBDataset.h:79
DBRow getRow(size_t row) const
Definition: DBDataset.h:131
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
int getRowNumber(DBChannelID_t ch) const
Definition: DBDataset.cxx:185
int GetChannelList(std::vector< DBChannelID_t > &channels) const
Definition: DBFolder.cxx:212
DBChannelID_t fCachedChannel
Definition: DBFolder.h:77
int fMaximumTimeout
Definition: DBFolder.h:68
const std::vector< value_type > & data() const
Definition: DBDataset.h:122
bool IsValid(const IOVTimeStamp &time) const
Definition: DBFolder.h:53
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
decltype(auto) values(Coll &&coll)
Range-for loop helper iterating across the values of the specified collection.
Int_t col[ntarg]
Definition: Style.C:29
std::string fURL2
Definition: DBFolder.h:62
const IOVTimeStamp & endTime() const
Definition: DBDataset.h:116
const std::vector< std::string > & colTypes() const
Definition: DBDataset.h:120
void DumpDataset(const DBDataset &data) const
Definition: DBFolder.cxx:714
bool CompareDataset(const DBDataset &data1, const DBDataset &data2) const
Definition: DBFolder.cxx:771
const IOVTimeStamp & beginTime() const
Definition: DBDataset.h:115
std::string fFolderName
Definition: DBFolder.h:63
double value
Definition: spectrum.C:18
std::string fTag
Definition: DBFolder.h:64
Filters for channels, events, etc.
const std::vector< DBChannelID_t > & channels() const
Definition: DBDataset.h:121
void * Dataset
Definition: DBFolder.h:12
bool isValid() const
Definition: DBDataset.h:77
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
long getLongData(size_t col) const
Definition: DBDataset.h:83
size_t GetColumn(const std::string &name) const
Definition: DBFolder.cxx:250
size_t ncols() const
Definition: DBDataset.h:118
int getColNumber(const std::string &name) const
Definition: DBDataset.cxx:225
static IOVTimeStamp MaxTimeStamp()
std::string fSQLitePath
Definition: DBFolder.h:67
DBFolder(const std::string &name, const std::string &url, const std::string &url2, const std::string &tag="", bool useqlite=false, bool testmode=false)
Definition: DBFolder.cxx:19
static IOVTimeStamp DecodeTimeStamp(DBTimeStamp_t ts)
Collection of exception classes for WebDBI.
Int_t ncols
Definition: plot.C:52
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
void GetSQLiteData(int t, DBDataset &data) const
Definition: DBFolder.cxx:351