Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OnlMonDBodbc.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file OnlMonDBodbc.cc
1 #include "OnlMonDBodbc.h"
2 #include "OnlMonDBReturnCodes.h"
3 #include "OnlMonDBVar.h"
4 
5 #include <onlmon/OnlMonBase.h> // for OnlMonBase
6 
7 #include <odbc++/connection.h>
9 #include <odbc++/drivermanager.h>
10 #include <odbc++/resultset.h> // for ResultSet
12 #include <odbc++/statement.h> // for Statement
13 #include <odbc++/types.h> // for SQLException, odbc
14 
15 #include <ctype.h> // for tolower
16 #include <algorithm>
17 #include <cstdio> // for printf
18 #include <ctime>
19 #include <fstream>
20 #include <iostream>
21 #include <sstream>
22 #include <utility> // for pair
23 
24 static const unsigned int DEFAULTCOLUMNS = 2;
25 //static const unsigned int COLUMNSPARVAR = 3;
26 static const std::string addvarname[3] = {"", "err", "qual"};
27 static const unsigned int MINUTESINTERVAL = 4;
28 
29 static odbc::Connection* con = nullptr;
30 
31 // #define VERBOSE
32 
34  : OnlMonBase(tablename)
35  , dbname("OnlMonDB")
36  , dbowner("phnxrc")
37  , dbpasswd("")
38  , table(tablename)
39 {
40  // table names are lower case only, so convert string to lowercase
41  // The bizarre cast here is needed for newer gccs
42  transform(table.begin(), table.end(), table.begin(), (int (*)(int)) tolower);
43 }
44 
46 {
47  delete con;
48  con = nullptr;
49 }
50 
52 {
53  if (GetConnection())
54  {
55  return -1;
56  }
57 
58  std::ostringstream cmd;
59  cmd << "SELECT * FROM pg_tables where tablename = '" << table << "'";
60  odbc::ResultSet* rs = nullptr;
61  odbc::Statement* stmt = con->createStatement();
62  try
63  {
64  rs = stmt->executeQuery(cmd.str());
65  }
66  catch (odbc::SQLException& e)
67  {
68  std::cout << "caught exception Message: " << e.getMessage() << std::endl;
69  }
70  int iret = 0;
71  if (!rs->next())
72  {
73  delete rs;
74  rs = nullptr;
75  if (verbosity > 0)
76  {
77  std::cout << "need to create table" << std::endl;
78  }
79  cmd.str("");
80  cmd << "CREATE TABLE " << table << "(date timestamp(0) with time zone NOT NULL, run int NOT NULL, primary key(date,run))";
81  try
82  {
83  stmt->executeUpdate(cmd.str());
84  }
85  catch (odbc::SQLException& e)
86  {
87  std::cout << "caught exception Message: " << e.getMessage() << std::endl;
88  }
89  }
90  else
91  {
92  if (verbosity > 0)
93  {
94  std::cout << "table " << table << " exists" << std::endl;
95  }
96  }
97  delete rs;
98  delete stmt;
99  return iret;
100 }
101 
102 int OnlMonDBodbc::CheckAndCreateTable(const std::map<const std::string, OnlMonDBVar*>& varmap)
103 {
104  if (GetConnection())
105  {
106  return -1;
107  }
108  if (CreateTable()) // check and create the table
109  {
110  return -1;
111  }
112  odbc::Statement* stmt = con->createStatement();
113  odbc::ResultSet* rs = nullptr;
114  std::ostringstream cmd;
115  int iret = 0;
116  cmd << "select * from " << table << " limit 1";
117  std::map<const std::string, OnlMonDBVar*>::const_iterator iter;
118  try
119  {
120  rs = stmt->executeQuery(cmd.str());
121  }
122  catch (odbc::SQLException& e)
123  {
124  std::cout << "caught exception Message: " << e.getMessage() << std::endl;
125  }
126  odbc::ResultSetMetaData* meta = rs->getMetaData();
127  unsigned int nocolumn = rs->getMetaData()->getColumnCount();
128  for (iter = varmap.begin(); iter != varmap.end(); ++iter)
129  {
130  std::string varname = iter->first;
131  // column names are lower case only, so convert string to lowercase
132  // The bizarre cast here is needed for newer gccs
133  transform(varname.begin(), varname.end(), varname.begin(), (int (*)(int)) tolower);
134  for (const auto & j : addvarname)
135  {
136  std::string thisvar = varname + j;
137  for (unsigned int i = DEFAULTCOLUMNS + 1; i <= nocolumn; i++)
138  {
139  if (meta->getColumnName(i) == thisvar)
140  {
141  if (verbosity > 0)
142  {
143  std::cout << thisvar << " is in table" << std::endl;
144  }
145  goto foundvar;
146  }
147  }
148  cmd.str("");
149  cmd << "ALTER TABLE " << table << " ADD COLUMN "
150  << thisvar << " real";
151  if (verbosity > 0)
152  {
153  std::cout << "executing sql command: " << cmd.str() << std::endl;
154  }
155 
156  try
157  {
158  odbc::Statement* chgtable = con->createStatement();
159  iret = chgtable->executeUpdate(cmd.str());
160  delete chgtable;
161  }
162  catch (odbc::SQLException& e)
163  {
164  std::cout << "Table " << table << " update failed" << std::endl;
165  std::cout << "Message: " << e.getMessage() << std::endl;
166  }
167 
168  foundvar:
169  continue;
170  }
171  }
172  delete rs;
173  delete stmt;
174  // check columns
175  return iret;
176 }
177 
179 {
180  if (GetConnection())
181  {
182  return -1;
183  }
184  std::string tablename = name;
185  // table names are lower case only, so convert string to lowercase
186  // The bizarre cast here is needed for newer gccs
187  transform(tablename.begin(), tablename.end(), tablename.begin(), (int (*)(int)) tolower);
188  std::cout << con->getMetaData()->getDatabaseProductVersion() << std::endl;
189  std::cout << con->getCatalog() << std::endl;
190  odbc::Statement* stmt = con->createStatement();
191  std::ostringstream cmd;
192  cmd << "DROP TABLE " << tablename;
193 
194  int iret = stmt->executeUpdate(cmd.str());
195  std::cout << "iret: " << iret << std::endl;
196  return iret;
197 }
198 
200 {
201  if (GetConnection())
202  {
203  return;
204  }
205 
206  //std::cout << con->getMetaData()-> getDatabaseProductVersion() << std::endl;
207  odbc::Statement* stmt = con->createStatement();
208  std::ostringstream cmd;
209  cmd << "SELECT * FROM " << table;
210  std::cout << "Executing " << cmd.str() << std::endl;
211  odbc::ResultSet* rs = stmt->executeQuery(cmd.str());
212  Dump(rs);
213  return;
214 }
215 
217 {
218  odbc::ResultSetMetaData* meta = rs->getMetaData();
219  unsigned int ncolumn = meta->getColumnCount();
220  while (rs->next())
221  {
222  odbc::Timestamp id = rs->getTimestamp(1);
223  int Name = rs->getInt(2);
224  std::cout << "TimeStamp: " << (id.toString()) << " Run #= " << Name << std::endl;
225  for (unsigned int i = DEFAULTCOLUMNS + 1; i <= ncolumn; i++)
226  {
227  float rval = rs->getFloat(i);
228  if (rs->wasNull())
229  {
230  std::cout << meta->getColumnName(i) << ": NULL" << std::endl;
231  }
232  else
233  {
234  std::cout << meta->getColumnName(i) << ": " << rval << std::endl;
235  }
236  }
237  }
238  try
239  {
240  rs->first();
241  }
242  catch (odbc::SQLException& e)
243  {
244  std::cout << "Exception caught" << std::endl;
245  std::cout << "Message: " << e.getMessage() << std::endl;
246  }
247 
248  return;
249 }
250 
251 int OnlMonDBodbc::Info(const char* name)
252 {
253  if (GetConnection())
254  {
255  return -1;
256  }
257 
258  std::cout << con->getMetaData()->getDatabaseProductVersion() << std::endl;
259  // if no argument is given print out list of tables
260  if (!name)
261  {
262  std::cout << "Driver: " << con->getMetaData()->getDriverName() << std::endl;
263  std::cout << "User: " << con->getMetaData()->getUserName() << std::endl;
264  std::string catalog = con->getMetaData()->getCatalogTerm();
265  std::cout << "Catalog: " << catalog << std::endl;
266  std::string schemapattern = con->getMetaData()->getSchemaTerm();
267  std::cout << "Schema: " << schemapattern << std::endl;
268  std::string tablenamepattern = con->getMetaData()->getTableTerm();
269  std::cout << "Table: " << tablenamepattern << std::endl;
270  std::vector<std::string> types;
271  odbc::ResultSet* rs = con->getMetaData()->getTableTypes();
272  while (rs->next())
273  {
274  std::cout << "1: " << rs->getString(1) << std::endl;
275  std::cout << "2: " << rs->getString(2) << std::endl;
276  std::cout << "3: " << rs->getString(3) << std::endl;
277  std::cout << "4: " << rs->getString(4) << std::endl;
278  std::cout << "5: " << rs->getString(5) << std::endl;
279  }
280  odbc::ResultSet* rs1 = con->getMetaData()->getTables(catalog, schemapattern, tablenamepattern, types);
281 
282  std::cout << "rs1: " << rs1 << std::endl;
283  // std::cout << rs->getMetaData()->getTableName(1) << std::endl;
284  while (rs1->next())
285  {
286  std::cout << "Table: " << rs->getString("TABLE_CAT") << std::endl;
287  std::cout << "Table: " << rs->getString(3) << std::endl;
288  }
289  }
290  else
291  {
292  odbc::Statement* stmt = con->createStatement();
293  std::string tablename = name;
294  // table names are lower case only, so convert string to lowercase
295  // The bizarre cast here is needed for newer gccs
296  transform(tablename.begin(), tablename.end(), tablename.begin(), (int (*)(int)) tolower);
297  std::ostringstream cmd;
298  cmd << "select * from " << tablename;
299  odbc::ResultSet* rs = stmt->executeQuery("select * from inttest");
300  std::cout << rs->getMetaData()->getColumnCount() << std::endl;
301  while (rs->next())
302  {
303  int id = rs->getInt(1);
304  float Name = rs->getFloat(2);
305  std::cout << "Row: " << rs->getRow() << ", id=" << id << " Name= " << Name << std::endl;
306  }
307  }
308  return 0;
309 }
310 
312 {
313  std::cout << "DB Name: " << dbname << std::endl;
314  std::cout << "DB Owner: " << dbowner << std::endl;
315  std::cout << "DB Pwd: " << dbpasswd << std::endl;
316  std::cout << "DB table: " << table << std::endl;
317  return;
318 }
319 
320 int OnlMonDBodbc::AddRow(const time_t ticks, const int runnumber, const std::map<const std::string, OnlMonDBVar*>& varmap)
321 {
322  // bail out when restarted before a run was taken - run=0, ticks=0
323  if (ticks == 0 || runnumber <= 0)
324  {
325  return -1;
326  }
327  std::map<const std::string, OnlMonDBVar*>::const_iterator iter;
328  int iret = 0;
329  int minutesinterval = MINUTESINTERVAL;
330  std::ostringstream cmd, cmd1, datestream;
331  odbc::Timestamp thistime(ticks);
332  odbc::Timestamp mintime;
333  odbc::Timestamp maxtime;
334 
335  if (GetConnection())
336  {
337  return -1;
338  }
339 
340  odbc::Statement* query = con->createStatement();
341 searchagain:
342  mintime.setTime(ticks - minutesinterval * 60);
343  maxtime.setTime(ticks + minutesinterval * 60);
344 #ifdef VERBOSE
345 
346  std::cout << "mintime stp: " << mintime.toString() << std::endl;
347  std::cout << "maxtime stp: " << maxtime.toString() << std::endl;
348 #endif
349 
350  cmd.str("");
351  datestream.str("");
352  datestream << "date > '" << mintime.toString()
353  << "' and date < '" << maxtime.toString() << "'";
354  cmd << "SELECT COUNT(*) FROM " << table << " WHERE run = "
355  << runnumber << " and " << datestream.str();
356 #ifdef VERBOSE
357 
358  std::cout << "cmd: " << cmd.str() << std::endl;
359 #endif
360 
361  odbc::ResultSet* rs = nullptr;
362 
363  try
364  {
365  rs = query->executeQuery(cmd.str());
366  }
367  catch (odbc::SQLException& e)
368  {
369  std::cout << "Exception caught" << std::endl;
370  std::cout << "Message: " << e.getMessage() << std::endl;
371  std::cout << "sql cmd: " << cmd.str() << std::endl;
372  }
373  int haverow = 0;
374  if (rs)
375  {
376  while (rs->next())
377  {
378  haverow = rs->getInt(1);
379 #ifdef VERBOSE
380 
381  std::cout << "found rows: " << haverow << std::endl;
382 #endif
383  }
384  delete rs;
385  }
386  if (haverow > 1)
387  {
388  minutesinterval = minutesinterval / 2;
389  goto searchagain;
390  }
391  else if (haverow == 1)
392  {
393  cmd.str("");
394  cmd << "SELECT * FROM " << table << " WHERE " << datestream.str();
395 #ifdef VERBOSE
396 
397  std::cout << "command: " << cmd.str() << std::endl;
398 #endif
399 
400  rs = query->executeQuery(cmd.str());
401  // if the following works, the query returned one or more rows
402  // in the given time interval
403  while (rs->next())
404  {
405  cmd.str("");
406  for (iter = varmap.begin(); iter != varmap.end(); ++iter)
407  {
408  if (iter->second->wasupdated())
409  {
410  std::string varqualname = iter->first + addvarname[2];
411  float varqual = iter->second->GetVar(2);
412  float sqlvarqual = rs->getFloat(varqualname);
413  if (varqual > sqlvarqual || rs->wasNull())
414  {
415  odbc::Statement* upd = con->createStatement();
416  // if there is only 1 row we do not need to worry which one to update
417  for (unsigned int j = 0; j < 3; j++)
418  {
419  cmd.str("");
420  cmd << "UPDATE " << table << " SET "
421  << iter->first << addvarname[j] << " = "
422  << iter->second->GetVar(j) << " WHERE "
423  << datestream.str();
424 #ifdef VERBOSE
425 
426  std::cout << "Command: " << cmd.str() << std::endl;
427 #endif
428 
429  int iret2 = upd->executeUpdate(cmd.str());
430  if (!iret2)
431  {
432  std::cout << __PRETTY_FUNCTION__ << "Update failed please send mail to pinkenburg@bnl.gov"
433  << std::endl;
434  std::cout << "And include the macro and the following info" << std::endl;
435  std::cout << "TableName: " << table << std::endl;
436  std::cout << "Variable: " << iter->first << addvarname[j] << std::endl;
437  std::cout << "Value: " << iter->second->GetVar(j) << std::endl;
438  std::cout << "TimeStamp: " << rs->getTimestamp(1).toString() << std::endl;
439  }
440  }
441  }
442  }
443  }
444  }
445  }
446  else
447  {
448  cmd.str("");
449  cmd << "INSERT INTO " << table << "(date, run";
450  cmd1 << "VALUES('" << thistime.toString() << "'," << runnumber;
451  int newval = 0;
452  for (iter = varmap.begin(); iter != varmap.end(); ++iter)
453  {
454  if (iter->second->wasupdated())
455  {
456  for (unsigned int j = 0; j < 3; j++)
457  {
458  cmd << ", " << iter->first << addvarname[j];
459  cmd1 << ", " << iter->second->GetVar(j);
460  newval++;
461  }
462  }
463  }
464  if (!newval)
465  {
466  printf("No updated values\n");
467  return -1;
468  }
469  cmd << ") ";
470  cmd1 << ")";
471  cmd << cmd1.str();
472 
473 #ifdef VERBOSE
474 
475  std::cout << cmd.str() << std::endl;
476 #endif
477 
478  odbc::Statement* stmt = con->createStatement();
479  try
480  {
481  stmt->executeUpdate(cmd.str());
482  }
483  catch (odbc::SQLException& e)
484  {
485  const std::string& errmsg = e.getMessage();
486  if (errmsg.find("Cannot insert a duplicate key into unique index") != std::string::npos)
487  {
488 #ifdef VERBOSE
489  std::cout << "Identical entry already in DB" << std::endl;
490 #endif
491  iret = 0;
492  }
493  else
494  {
495  std::cout << __PRETTY_FUNCTION__ << " DB Error in execute stmt: " << e.getMessage() << std::endl;
496  std::ofstream savesql("lostupdates.sql", std::ios_base::app);
497  savesql << cmd.str() << std::endl;
498  savesql.close();
499  iret = -1;
500  }
501  }
502  }
503  return iret;
504 }
505 
506 int OnlMonDBodbc::GetVar(const time_t begin, const time_t end, const std::string& varname, std::vector<time_t>& timestp, std::vector<int>& runnumber, std::vector<float>& var, std::vector<float>& varerr)
507 {
508  if (GetConnection())
509  {
510  return DBNOCON;
511  }
512  int iret = 0;
513 
514  odbc::Statement* query = con->createStatement();
515  odbc::Timestamp mintime(begin);
516  odbc::Timestamp maxtime(end);
517  std::string varnameerr = varname + addvarname[1];
518  std::ostringstream cmd, datestream;
519  datestream << "date > '" << mintime.toString()
520  << "' and date < '" << maxtime.toString() << "'";
521  cmd << "SELECT COUNT(*) FROM " << table << " WHERE " << datestream.str();
522 
523 #ifdef VERBOSE
524  std::cout << "command: " << cmd.str() << std::endl;
525 #endif
526 
527  odbc::ResultSet* rs;
528  try
529  {
530  rs = query->executeQuery(cmd.str());
531  }
532  catch (odbc::SQLException& e)
533  {
534  std::cout << "Exception caught, probably your table "
535  << table
536  << " does not exist" << std::endl;
537  std::cout << "Message: " << e.getMessage() << std::endl;
538  varerr.resize(0);
539  var.resize(0);
540  timestp.resize(0);
541  runnumber.resize(0);
542  return -1;
543  }
544  int nrows = 0;
545  while (rs->next())
546  {
547  nrows = rs->getInt(1);
548  }
549  timestp.resize(nrows);
550  runnumber.resize(nrows);
551  var.resize(nrows);
552  varerr.resize(nrows);
553  if (!nrows)
554  {
555  return DBNOENTRIES;
556  }
557  delete rs;
558  cmd.str("");
559  // get data in ascending date order (earliest time first)
560  cmd << "SELECT date, run, " << varname << ", " << varnameerr
561  << " FROM " << table << " WHERE "
562  << datestream.str() << " ORDER BY date ASC";
563 #ifdef VERBOSE
564 
565  std::cout << "Command: " << cmd.str() << std::endl;
566 #endif
567 
568  try
569  {
570  rs = query->executeQuery(cmd.str());
571  }
572  catch (odbc::SQLException& e)
573  {
574  std::cout << "Exception caught, probably your variable "
575  << varname << " or the table " << table
576  << " does not exist" << std::endl;
577  std::cout << "Message: " << e.getMessage() << std::endl;
578  varerr.resize(0);
579  var.resize(0);
580  timestp.resize(0);
581  runnumber.resize(0);
582  return -3;
583  }
584  unsigned int index = 0;
585  int filledrows = nrows;
586  while (rs->next())
587  {
588  float val = rs->getFloat(3);
589  if (rs->wasNull())
590  {
591  filledrows--;
592  continue;
593  }
594  timestp[index] = rs->getTimestamp(1).getTime();
595  runnumber[index] = rs->getInt(2);
596  var[index] = val;
597  varerr[index] = rs->getFloat(4);
598  index++;
599  }
600  if (filledrows != nrows)
601  {
602  varerr.resize(filledrows);
603  var.resize(filledrows);
604  timestp.resize(filledrows);
605  runnumber.resize(filledrows);
606  }
607  return iret;
608 }
609 
611 {
612  if (con)
613  {
614  return 0;
615  }
616  try
617  {
618  con = odbc::DriverManager::getConnection(dbname.c_str(), dbowner.c_str(), dbpasswd.c_str());
619  }
620  catch (odbc::SQLException& e)
621  {
622  std::cout << __PRETTY_FUNCTION__
623  << " Exception caught during DriverManager::getConnection" << std::endl;
624  std::cout << "Message: " << e.getMessage() << std::endl;
625  if (con)
626  {
627  delete con;
628  con = nullptr;
629  }
630  return -1;
631  }
632  printf("opened DB connection\n");
633  return 0;
634 }