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