VSQLManager_MySQL.h
Go to the documentation of this file.
1 #ifndef _det_VSQLManager_MySQL_h_
2 #define _det_VSQLManager_MySQL_h_
3 
4 #include <stddef.h>
5 #include <ctype.h>
6 #ifdef __GNUC__
7 # include <cxxabi.h>
8 #endif
9 #include <sstream>
10 #include <fstream>
11 
12 #include <boost/tuple/tuple.hpp>
13 #include <boost/lexical_cast.hpp>
14 
15 #include <mysql/mysql.h>
16 
17 #include <det/VManager.h>
18 #include <utl/RealTimeStopwatch.h>
19 
20 
21 /* Use this macro to call the generic GetDBData() method of the VSQLManager */
22 #define VSQLMANAGER_GETDATA_GETDBDATA(_T_...) VMANAGER_GETDATA_CALL(GetDBData, _T_)
23 
24 
25 namespace det {
26 
45  class VSQLManager : public det::VManager {
46 
47  public:
49  virtual ~VSQLManager() { Close(); }
50 
51  static void SetGlobalLogQueries(const int q) { fgGlobalLogQueries = q; }
52 
53  protected:
54  void Close();
55 
56  virtual void Init(const std::string& configLink);
57 
58  void Connect() const;
59 
61  Status Query(const std::ostringstream& os, const std::string& what = "") const
62  { return Query(os.str(), what); }
63 
64  Status Query(const std::string& query, const std::string& what = "") const;
65 
66  Status Query(const std::ostringstream& os, const std::ostringstream& what) const
67  { return Query(os.str(), what.str()); }
68 
70  template<typename T>
71  Status
72  FetchRow(T& result, const bool free = true)
73  const
74  {
75  const MYSQL_ROW row = FetchRow();
76  if (row && row[0]) {
77  try {
78  result = boost::lexical_cast<T>(row[0]);
79  } catch (boost::bad_lexical_cast&) {
80  BadLexicalCast<T>(row[0], "preserving original value");
81  }
82  if (free)
83  FreeResult();
84  return eFound;
85  }
86  FreeResult();
87  return eNotFound;
88  }
89 
91  template<typename T>
92  Status
93  FetchRow(std::vector<T>& result, const bool free = true)
94  const
95  {
96  const MYSQL_ROW row = FetchRow();
97  if (row) {
98  const int n = NumFields();
99  result.resize(n);
100  for (int i = 0; i < n; ++i) {
101  try {
102  if (!row[i]) {
103  result[i] = boost::lexical_cast<T>("");
104  ERROR("Empty field returned from sql-query!");
105  } else {
106  result[i] = boost::lexical_cast<T>(row[i]);
107  }
108  } catch (boost::bad_lexical_cast&) {
109  BadLexicalCast<T>(row[i], "preserving original value");
110  }
111  }
112  if (free)
113  FreeResult();
114  return eFound;
115  }
116  FreeResult();
117  return eNotFound;
118  }
119 
121  template<typename TH, typename TT>
122  Status
123  FetchRowMany(boost::tuples::cons<TH, TT>& tuple, const bool free = true)
124  const
125  {
126  const MYSQL_ROW row = FetchRow();
127  if (row) {
128  const Status status = FetchRowTuple(row, tuple);
129  if (status == eNotFound || free)
130  FreeResult();
131  return status;
132  }
133  FreeResult();
134  return eNotFound;
135  }
136 
138  template<typename T>
139  Status
140  FetchColumn(std::vector<T>& result)
141  const
142  {
143  MYSQL_ROW row;
144  while ((row = FetchRow()))
145  if (row[0]) {
146  try {
147  result.push_back(boost::lexical_cast<T>(row[0]));
148  } catch (boost::bad_lexical_cast&) {
149  BadLexicalCast<T>(row[0], "some rows will be missing");
150  }
151  } else {
152  FreeResult();
153  return eNotFound;
154  }
155  FreeResult();
156  return eFound;
157  }
158 
160  template<typename T> Status FetchNextRow(T& result) const
161  { return FetchRow(result, false); }
162 
164  template<typename TH, typename TT>
165  Status FetchNextRowMany(boost::tuples::cons<TH, TT>& result) const
166  { return FetchRowMany(result, false); }
167 
169  unsigned int NumFields() const
170  { return mysql_num_fields(NeedsResult()); }
171 
173  size_t NumRows() const
174  { return mysql_num_rows(NeedsResult()); }
175 
177  virtual Status GetDBResFundamental(const std::string&, const std::string&, const IndexMap&) const
178  { ERROR("Should not be used!"); return eNotFound; }
179 
180  template<typename T>
181  Status
182  GetDBData(T& returnData,
183  const std::string& tableName,
184  const std::string& columnName,
185  const IndexMap& componentIndex)
186  const
187  {
188  if (GetDBResFundamental(tableName, columnName, componentIndex) == eNotFound)
189  return eNotFound;
190 
191  return FetchRow(returnData);
192  }
193 
195  virtual Status GetDBResVector(const std::string&,
196  const std::string&,
197  const IndexMap&) const
198  { ERROR("Should not be used!"); return eNotFound; }
199 
200  template<typename T>
201  Status
202  GetDBData(std::vector<T>& returnData,
203  const std::string& tableName,
204  const std::string& columnName,
205  const IndexMap& componentIndex)
206  const
207  {
208  if (GetDBResVector(tableName, columnName, componentIndex) == eNotFound)
209  return eNotFound;
210 
211  return FetchColumn(returnData);
212  }
213 
214  mutable std::string fDatabaseSoftwareVersion;
215 
216  void
217  FreeResult()
218  const
219  {
220  if (fMySQLResult) {
221  mysql_free_result(fMySQLResult);
222  fMySQLResult = nullptr;
223  }
224  }
225 
226  static std::string MergeIndexMap(const IndexMap& componentIndex);
227 
228  private:
229  MYSQL_RES*
230  NeedsResult()
231  const
232  {
233  if (fMySQLResult)
234  return fMySQLResult;
235  const std::string err = "Empty MySQL result queue.";
236  ERROR(err);
237  throw utl::IOFailureException(err);
238  }
239 
240  protected:
241  MYSQL_ROW FetchRow() const { return mysql_fetch_row(NeedsResult()); }
242 
243  private:
245  Status FetchRowTuple(const MYSQL_ROW, const boost::tuples::null_type&,
246  const int) const
247  { return eFound; }
248 
249  template<typename TH, typename TT>
250  Status
251  FetchRowTuple(const MYSQL_ROW row, boost::tuples::cons<TH, TT>& tuple,
252  const int index = 0)
253  const
254  {
255  if (row[index]) {
256  try {
257  tuple.get_head() = boost::lexical_cast<TH>(row[index]);
258  } catch (boost::bad_lexical_cast&) {
259  BadLexicalCast<TH>(row[index], "some columns will be missing");
260  }
261  return FetchRowTuple(row, tuple.get_tail(), index+1);
262  } else
263  return eNotFound;
264  }
265 
266  template<typename T>
267  static
268  void
269  BadLexicalCast(const char* const row, const std::string& action)
270  {
271  std::ostringstream err;
272  err << "Bad lexical cast from '";
273  int i = 30;
274  for (int j = 0; i > 0 && row[j]; ++j) {
275  err << (isprint(row[j]) ? row[j] : '.');
276  --i;
277  }
278  if (i)
279  err << "[truncated]";
280  err << "' to ";
281 #ifdef __GNUC__
282  int status;
283  err << abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);
284 #else
285  err << typeid(T).name();
286 #endif
287  err << "; " << action << '.';
288  ERROR(err);
289  }
290 
291  // database info
292  mutable std::string fDatabaseServer;
293  mutable std::string fDatabaseUserName;
294  mutable std::string fDatabasePassword;
295  mutable std::string fDatabaseName;
296 
297  mutable int fPort = -1;
298 
299  mutable MYSQL* fMySQL = nullptr;
300  mutable MYSQL_RES* fMySQLResult = nullptr;
301 
303  mutable int fLogQueries = 0;
304  mutable std::ofstream* fLogQueryStream = nullptr;
305  static int fgGlobalLogQueries;
306 
307  // disable copying
308  VSQLManager(const VSQLManager&);
310 
311  };
312 
313 }
314 
315 
316 #endif
Status GetDBData(T &returnData, const std::string &tableName, const std::string &columnName, const IndexMap &componentIndex) const
virtual Status GetDBResVector(const std::string &, const std::string &, const IndexMap &) const
overload this in all derived managers that need it
Status GetDBData(std::vector< T > &returnData, const std::string &tableName, const std::string &columnName, const IndexMap &componentIndex) const
Status FetchRowTuple(const MYSQL_ROW, const boost::tuples::null_type &, const int) const
stop taking tuples
std::ofstream * fLogQueryStream
Status FetchRowMany(boost::tuples::cons< TH, TT > &tuple, const bool freeResult=true) const
Get a tuple of values from the first row of an SQLite query result.
Status FetchNextRow(T &result) const
Fetch first item (may be a tuple) from current row.
const std::string err
static void BadLexicalCast(const char *const row, const std::string &action)
VSQLManager & operator=(const VSQLManager &)
size_t NumRows() const
Total number of rows in the current query result.
std::string fDatabaseSoftwareVersion
std::string fDatabasePassword
Interface for detector managers.
Definition: VManager.h:115
std::string fDatabaseUserName
std::string fDatabaseServer
Status Query(const std::ostringstream &os, const std::ostringstream &what) const
Base class to report exceptions in IO.
virtual void Init(const std::string &configLink)
Manager Initialization. configLink is the CentralConfig hook for the configuration file...
Interface for detector managers that use MySQL.
static int fgGlobalLogQueries
const Data result[]
std::string fDatabaseName
Database filename.
MYSQL_RES * fMySQLResult
Status FetchColumn(std::vector< T > &data) const
Get the first item from many rows of an SQLite query result.
void Connect() const
static void SetGlobalLogQueries(const int q)
MYSQL_ROW FetchRow() const
Status FetchNextRowMany(boost::tuples::cons< TH, TT > &result) const
workaround
Status FetchRowTuple(const MYSQL_ROW row, boost::tuples::cons< TH, TT > &tuple, const int index=0) const
virtual Status GetDBResFundamental(const std::string &, const std::string &, const IndexMap &) const
overload this in all derived managers that need it
std::map< std::string, std::string > IndexMap
Definition: VManager.h:133
Status Query(const std::ostringstream &os, const std::string &what="") const
query MySQL
static std::string MergeIndexMap(const IndexMap &componentIndex)
utl::RealTimeStopwatch fTime
Status
Specifies success or (eventually) various possible failure modes.
Definition: VManager.h:127
unsigned int NumFields() const
Number of fields (columns) in the current query result.

, generated on Tue Sep 26 2023.