Belle II Software  release-05-02-19
PostgreSQLInterface.cc
1 #include "daq/slc/psql/PostgreSQLInterface.h"
2 #include "daq/slc/base/ConfigFile.h"
3 
4 #ifndef NOT_USE_PSQL
5 #include <pgsql/libpq-fe.h>
6 #endif
7 
8 #include <daq/slc/base/StringUtil.h>
9 #include <daq/slc/database/DBHandlerException.h>
10 
11 #include <daq/slc/system/LockGuard.h>
12 
13 using namespace Belle2;
14 
15 PostgreSQLInterface::PostgreSQLInterface(const std::string& host,
16  const std::string& database,
17  const std::string& user,
18  const std::string& password,
19  int port)
20 {
21  init(host, database, user, password, port);
22  m_sq_conn = NULL;
23  m_sq_result = NULL;
24 }
25 
26 PostgreSQLInterface::PostgreSQLInterface()
27 {
28  ConfigFile config("slowcontrol");
29  init(config.get("database.host"),
30  config.get("database.dbname"),
31  config.get("database.user"),
32  config.get("database.password"),
33  config.getInt("database.port"));
34  m_sq_conn = NULL;
35  m_sq_result = NULL;
36 }
37 
38 void PostgreSQLInterface::connect()
39 {
40 #ifndef NOT_USE_PSQL
41  if (isConnected()) return;
42 
43  {
44  LockGuard lockGuard(m_mutex);
45  m_sq_conn = PQconnectdb(StringUtil::form("host=%s dbname=%s user=%s password=%s port=%d",
46  m_host.c_str(), m_database.c_str(),
47  m_user.c_str(), m_password.c_str(),
48  m_port).c_str());
49  }
50 
51  if (PQstatus(m_sq_conn) == CONNECTION_BAD) {
52  DBHandlerException exception("Failed to connect to the database : %s",
53  PQerrorMessage(m_sq_conn));
54  close();
55  throw exception;
56  }
57 #else
58  throw (DBHandlerException("PGLIB is not available"));
59 #endif
60 }
61 
62 bool PostgreSQLInterface::isConnected()
63 {
64 #ifndef NOT_USE_PSQL
65  LockGuard lockGuard(m_mutex);
66  bool connected = m_sq_conn != NULL && PQstatus(m_sq_conn) == CONNECTION_OK;
67  return connected;
68 #else
69  return false;
70 #endif
71 }
72 
73 void PostgreSQLInterface::execute_imp(const char* command)
74 {
75  clear();
76 #ifndef NOT_USE_PSQL
77  LockGuard lockGuard(m_mutex);
78  m_sq_result = PQexec(m_sq_conn, command);
79  ExecStatusType status = PQresultStatus(m_sq_result);
80  if (status == PGRES_FATAL_ERROR) {
81  // Need to pre-generate exception to avoid data race
82  // on PQerrorMessage.
83  DBHandlerException exception("Failed to execute command : %s (%s)",
84  command, PQerrorMessage(m_sq_conn));
85  throw (exception);
86  }
87 #else
88  throw (DBHandlerException("libpg is not available"));
89 #endif
90 }
91 
92 DBRecordList PostgreSQLInterface::loadRecords()
93 {
94 #ifndef NOT_USE_PSQL
95  LockGuard lockGuard(m_mutex);
96  if (PQresultStatus(m_sq_result) != PGRES_TUPLES_OK) {
97  throw (DBHandlerException("DB records are not ready for reading"));
98  }
99  const size_t nrecords = PQntuples(m_sq_result);
100  const size_t nfields = PQnfields(m_sq_result);
101  m_record_v = DBRecordList();
102  std::vector<std::string> name_v;
103  for (size_t ifield = 0; ifield < nfields; ifield++) {
104  const char* name = PQfname(m_sq_result, ifield);
105  if (name != NULL) name_v.push_back(name);
106  }
107  for (size_t irecord = 0; irecord < nrecords; irecord++) {
108  DBRecord record;
109  for (size_t ifield = 0; ifield < nfields; ifield++) {
110  if (!PQgetisnull(m_sq_result, irecord, ifield)) {
111  const char* value = PQgetvalue(m_sq_result, irecord, ifield);
112  if (value != NULL) {
113  record.add(name_v[ifield], value);
114  }
115  }
116  }
117  m_record_v.push_back(record);
118  }
119 
120  // Vector copy must be done before mutex release,
121  // otherwise data race is introduced.
122  DBRecordList ret(m_record_v);
123 
124  return ret;
125 #else
126  throw (DBHandlerException("libpg is not available"));
127 #endif
128 }
129 
130 void PostgreSQLInterface::clear()
131 {
132 #ifndef NOT_USE_PSQL
133  LockGuard lockGuard(m_mutex);
134  if (m_sq_result != NULL) {
135  PQclear(m_sq_result);
136  m_sq_result = NULL;
137  }
138 #else
139  throw (DBHandlerException("libpg is not available"));
140 #endif
141 }
142 
143 void PostgreSQLInterface::close()
144 {
145  clear();
146 #ifndef NOT_USE_PSQL
147  LockGuard lockGuard(m_mutex);
148  if (m_sq_conn != NULL) {
149  PQfinish(m_sq_conn);
150  m_sq_conn = NULL;
151  }
152 #else
153  throw (DBHandlerException("libpg is not available"));
154 #endif
155 }
156 
157 bool PostgreSQLInterface::checkTable(const std::string& tablename)
158 {
159 #ifndef NOT_USE_PSQL
160  execute("select relname from pg_stat_user_tables where relname='%s';",
161  tablename.c_str());
162  DBRecordList ret(loadRecords());
163  return ret.size() > 0;
164 #else
165  throw (DBHandlerException("libpg is not available"));
166 #endif
167 }
168 
169 DBFieldTypeList PostgreSQLInterface::getTableContents(const std::string& tablename)
170 {
171 #ifndef NOT_USE_PSQL
172  DBFieldTypeList name_m;
173  execute("select attname, typname from pg_class, pg_attribute, pg_type "
174  "where relkind ='r'and relname = '%s' and attrelid = relfilenode "
175  "and attnum > 0 and pg_type.oid = atttypid;", tablename.c_str());
176  DBRecordList ret(loadRecords());
177  for (size_t i = 0; i < ret.size(); i++) {
178  name_m.insert(DBFieldTypeList::value_type(ret[i].get("attname"),
179  ret[i].get("typname")));
180  }
181  return name_m;
182 #else
183  throw (DBHandlerException("libpg is not available"));
184 #endif
185 }
Belle2::DBHandlerException
Definition: DBHandlerException.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::ConfigFile
Definition: ConfigFile.h:15