JAPAn
Just Another Parity Analyzer
Loading...
Searching...
No Matches
QwDatabase.h
Go to the documentation of this file.
1/*!
2 * \file QwDatabase.h
3 * \brief A class for handling connections to the Qweak database.
4 *
5 * \author Damon Spayde
6 * \date 2010-01-07
7 */
8
9#pragma once
10
11// System headers
12#include <map>
13#include <memory>
14#include <vector>
15#include <string>
16#include <typeinfo>
17#include <variant>
18
19// Third Party Headers
20#ifdef __USE_DATABASE__
21#ifdef __USE_SQLPP11__
22#include <sqlpp11/sqlpp11.h>
23#ifdef __USE_DATABASE_MYSQL__
24#include <sqlpp11/mysql/mysql.h>
25#endif // __USE_DATABASE_MYSQL__
26#ifdef __USE_DATABASE_SQLITE3__
27#include <sqlpp11/sqlite3/sqlite3.h>
28#endif // __USE_DATABASE_SQLITE3__
29#ifdef __USE_DATABASE_POSTGRESQL__
30#include <sqlpp11/postgresql/postgresql.h>
31#endif // __USE_DATABASE_POSTGRESQL__
32#endif // __USE_SQLPP11__
33#ifdef __USE_SQLPP23__
34#include <sqlpp23/sqlpp23.h>
35#ifdef __USE_DATABASE_MYSQL__
36#include <sqlpp23/mysql/mysql.h>
37#endif // __USE_DATABASE_MYSQL__
38#ifdef __USE_DATABASE_SQLITE3__
39#include <sqlpp23/sqlite3/sqlite3.h>
40#endif // __USE_DATABASE_SQLITE3__
41#ifdef __USE_DATABASE_POSTGRESQL__
42#include <sqlpp23/postgresql/postgresql.h>
43#endif // __USE_DATABASE_POSTGRESQL__
44
45// Compatibility shims for sqlpp23 to support sqlpp11 syntax
46namespace sqlpp {
47 // Make std::nullopt available as sqlpp::null for compatibility
48 static constexpr auto null = std::nullopt;
49}
50
51// Compatibility helper for result field null checking
52// For sqlpp11: use free function is_null() to call the member function .is_null()
53// For sqlpp23: result fields are std::optional<T>, provide is_null() via ADL
54template<typename T>
55constexpr bool is_null(const std::optional<T>& opt) {
56 return !opt.has_value();
57}
58
59#endif // __USE_SQLPP23__
60#endif // __USE_DATABASE__
61
62// ROOT headers
63#include "TString.h"
64
65// Qweak headers
66#include "QwTypes.h"
67#include "QwLog.h"
68#include "QwColor.h"
69#include "QwOptions.h"
70
71// Forward declarations
72class QwDatabase;
73
74/**
75 * \class QwScopedConnection
76 * \ingroup QwAnalysis
77 * \brief A RAII-style scoped database connection
78 *
79 * This class provides automatic connection management using RAII principles.
80 * The connection is established when the object is created and automatically
81 * disconnected when the object goes out of scope.
82 */
84private:
87
88public:
89 explicit QwScopedConnection(QwDatabase* db);
91
92 // Delete copy constructor and assignment operator to prevent copying
95
96 // Allow move constructor and assignment
97 QwScopedConnection(QwScopedConnection&& other) noexcept;
99
100 // Provide access to the database interface
102 const QwDatabase* operator->() const { return fDatabase; }
104 const QwDatabase& operator*() const { return *fDatabase; }
105
106 // Check if connection is valid
107 bool IsConnected() const;
108};
109
110/**
111 * \class QwDatabase
112 * \ingroup QwAnalysis
113 * \brief A database interface class
114 *
115 * This class provides the connection to the Qweak database to other objects
116 * in the Qweak analyzer. A static global object gQwDatabase is used to
117 * provide these services.
118 *
119 */
120
122 private:
124#ifdef __USE_DATABASE_SQLITE3__
125 , kQwDatabaseSQLite3
126#endif // __USE_DATABASE_SQLITE3__
127#ifdef __USE_DATABASE_MYSQL__
128 , kQwDatabaseMySQL
129#endif // __USE_DATABASE_MYSQL__
130#ifdef __USE_DATABASE_POSTGRESQL__
131 , kQwDatabasePostgreSQL
132#endif // __USE_DATABASE_POSTGRESQL__
133 };
134 EQwDBType fDBType = kQwDatabaseNone; //!< Type of database backend to use
135
136 // Define connection types conditionally
137#ifdef __USE_DATABASE_SQLITE3__
138 using SQLiteConnection = std::shared_ptr<sqlpp::sqlite3::connection>;
139#endif
140#ifdef __USE_DATABASE_MYSQL__
141 using MySQLConnection = std::shared_ptr<sqlpp::mysql::connection>;
142#endif
143#ifdef __USE_DATABASE_POSTGRESQL__
144 using PostgreSQLConnection = std::shared_ptr<sqlpp::postgresql::connection>;
145#endif
146
147 // Build the variant type conditionally
148 using DatabaseConnection = std::variant<
149 std::monostate // Always include monostate as fallback
150#ifdef __USE_DATABASE_SQLITE3__
151 , SQLiteConnection
152#endif
153#ifdef __USE_DATABASE_MYSQL__
154 , MySQLConnection
155#endif
156#ifdef __USE_DATABASE_POSTGRESQL__
157 , PostgreSQLConnection
158#endif
159 >;
160
161 // Return type for QuerySelect that supports all possible result types
162 template<typename Statement>
163 using QuerySelectReturnType = std::variant<
164 std::monostate // Always include monostate as fallback
165#ifdef __USE_DATABASE_SQLITE3__
166 , decltype((*std::declval<SQLiteConnection>())(std::declval<Statement>()))
167#endif
168#ifdef __USE_DATABASE_MYSQL__
169 , decltype((*std::declval<MySQLConnection>())(std::declval<Statement>()))
170#endif
171#ifdef __USE_DATABASE_POSTGRESQL__
172 , decltype((*std::declval<PostgreSQLConnection>())(std::declval<Statement>()))
173#endif
174 >;
175
177
178 private:
179 // Enum to control connection checking behavior
180 enum class EConnectionCheck : bool {
181 kUnchecked = false,
182 kChecked = true
183 };
184
185 // Unified helper function to abstract the visitor pattern for database operations
186 template<EConnectionCheck CheckConnection = EConnectionCheck::kChecked, typename Lambda>
187 auto VisitConnection(Lambda&& lambda) {
188 return std::visit([&lambda](auto& connection) -> decltype(lambda(connection)) {
189 using T = std::decay_t<decltype(connection)>;
190 if constexpr (std::is_same_v<T, std::monostate>) {
191 if constexpr (CheckConnection == EConnectionCheck::kChecked) {
192 throw std::runtime_error("Database not connected (no backend available)");
193 } else {
194 // For unchecked mode with monostate, return appropriate default
195 if constexpr (std::is_void_v<decltype(lambda(connection))>) {
196 return; // Return void for void lambdas
197 } else {
198 return decltype(lambda(connection)){}; // Return default-constructed value
199 }
200 }
201 } else {
202 if constexpr (CheckConnection == EConnectionCheck::kChecked) {
203 if (!connection) {
204 throw std::runtime_error("Database not connected");
205 }
206 }
207 return lambda(connection);
208 }
209 }, fDBConnection);
210 }
211
212 public:
213
214 // Helper function to iterate over QuerySelect results safely
215 template<typename Statement, typename Lambda>
216 void QuerySelectForEachResult(const Statement& statement, Lambda&& lambda) {
217 auto results = QuerySelect(statement);
218 ForEachResult(results, std::forward<Lambda>(lambda));
219 }
220
221 // Overload to work with already-executed query results
222 template<typename QueryResult, typename Lambda>
223 void ForEachResult(QueryResult& result, Lambda&& lambda) const {
224 std::visit([&lambda](auto& res) {
225 using T = std::decay_t<decltype(res)>;
226 if constexpr (!std::is_same_v<T, std::monostate>) {
227 for (const auto& row : res) {
228 lambda(row);
229 }
230 }
231 // If T is std::monostate, do nothing (no results to iterate over)
232 }, result);
233 }
234
235 // Helper function to count QuerySelect results safely
236 template<typename Statement>
237 size_t QuerySelectCountResults(const Statement& statement) {
238 size_t count = 0;
239 QuerySelectForEachResult(statement, [&count](const auto& row) {
240 (void)row; // Suppress unused variable warning
241 count++;
242 });
243 return count;
244 }
245
246 // Overload to work with already-executed query results
247 template<typename QueryResult>
248 size_t CountResults(QueryResult& result) const {
249 size_t count = 0;
250 ForEachResult(result, [&count](const auto& row) {
251 (void)row; // Suppress unused variable warning
252 count++;
253 });
254 return count;
255 }
256
257 // Helper function to get first result safely (returns optional-like behavior)
258 template<typename Statement, typename Lambda>
259 bool QuerySelectForFirstResult(const Statement& statement, Lambda&& lambda) {
260 bool found = false;
261 QuerySelectForEachResult(statement, [&lambda, &found](const auto& row) {
262 if (!found) { // Only process first result
263 lambda(row);
264 found = true;
265 }
266 });
267 return found;
268 }
269
270 // Overload to work with already-executed query results
271 template<typename QueryResult, typename Lambda>
272 bool ForFirstResult(QueryResult& result, Lambda&& lambda) const {
273 bool found = false;
274 ForEachResult(result, [&lambda, &found](const auto& row) {
275 if (!found) { // Only process first result
276 lambda(row);
277 found = true;
278 }
279 });
280 return found;
281 }
282
283 // Specialized helper for QuerySelect that returns a variant of all possible result types
284 template<typename Statement, typename Lambda>
286 using ReturnVariant = QuerySelectReturnType<Statement>;
287 return std::visit([&lambda](auto& connection) -> ReturnVariant {
288 using T = std::decay_t<decltype(connection)>;
289 if constexpr (std::is_same_v<T, std::monostate>) {
290 throw std::runtime_error("Database not connected (no backend available)");
291 } else {
292 if (!connection) {
293 throw std::runtime_error("Database not connected");
294 }
295 return ReturnVariant{lambda(connection)};
296 }
297 }, fDBConnection);
298 }
299
300 public:
301
302 QwDatabase(const string &major = "00", const string &minor = "00", const string &point = "0000"); //!< Simple constructor
303 QwDatabase(QwOptions &options, const string &major = "00", const string &minor = "00", const string &point = "0000"); //!< Constructor with QwOptions object
304
305 virtual ~QwDatabase(); //!< Destructor
306
307 void SetAccessLevel(string accesslevel); //!< Sets the access level flag based on string labels: "off", "ro", "rw".
308
311
312 Bool_t Connect(); //!< Open a connection to the database using the predefined parameters.
313 void Disconnect() {
315 using T = std::decay_t<decltype(conn)>;
316 if constexpr (!std::is_same_v<T, std::monostate>) {
317 if (conn) {
318 conn.reset();
319 }
320 }
321 });
322 }; //<! Close an open database connection
323 Bool_t Connected() {
324 return VisitConnection<EConnectionCheck::kUnchecked>([](const auto& conn) -> bool {
325 using T = std::decay_t<decltype(conn)>;
326 if constexpr (std::is_same_v<T, std::monostate>) {
327 return false;
328 } else {
329 return conn != nullptr;
330 }
331 });
332 }
333
334 //!< Get a scoped connection that automatically disconnects when destroyed
338 const string GetServerVersion() {
339 // FIXME (wdconinc) implement server_version();
340 return "";
341 }; //<! Get database server version
342 static void DefineOptions(QwOptions& options); //!< Defines available class options for QwOptions
343 void ProcessOptions(QwOptions &options); //!< Processes the options contained in the QwOptions object.
344 void ProcessOptions(const EQwDBType& dbtype, const TString& dbname, const TString& username, const TString& passwd, const TString& dbhost="localhost", const Int_t dbport = 0, const TString& accesslevel = "ro"); //!< Processes database options
345
346 // Separate methods for different query types to avoid std::visit return type issues
347 template<typename Statement>
348 size_t QueryCount(const Statement& statement) {
349 return VisitConnection<EConnectionCheck::kChecked>([&statement](auto& connection) -> size_t {
350 using T = std::decay_t<decltype(connection)>;
351 if constexpr (!std::is_same_v<T, std::monostate>) {
352 auto result = (*connection)(statement);
353 size_t count = 0;
354 for (const auto& row : result) {
355 (void)row; // Suppress unused variable warning
356 count++;
357 }
358 return count;
359 }
360 // This should never be reached due to VisitConnection logic
361 throw std::runtime_error("Unreachable: monostate in QueryCount lambda");
362 });
363 }
364
365 template<typename Statement>
366 bool QueryExists(const Statement& statement) {
367 return QueryCount(statement) > 0;
368 } //<! Generate a query to check existence in the database.
369
370 template<typename Statement>
371 auto QuerySelect(const Statement& statement) {
372 return VisitConnectionForSelect<Statement>([&statement](auto& connection) {
373 using T = std::decay_t<decltype(connection)>;
374 if constexpr (!std::is_same_v<T, std::monostate>) {
375 return (*connection)(statement);
376 }
377 // This should never be reached due to VisitConnectionForSelect logic
378 throw std::runtime_error("Unreachable: monostate in QuerySelect lambda");
379 });
380 } //<! Execute a SELECT statement and return the result.
381
382 template<typename Statement>
383 void QueryExecute(const Statement& statement) {
384 VisitConnection<EConnectionCheck::kChecked>([&statement](auto& connection) {
385 using T = std::decay_t<decltype(connection)>;
386 if constexpr (!std::is_same_v<T, std::monostate>) {
387 (*connection)(statement);
388 }
389 });
390 } //<! Execute a statement without returning a result.
391
392 template<typename InsertStatement>
393 uint64_t QueryInsertAndGetId(const InsertStatement& statement) {
394 return VisitConnection<EConnectionCheck::kChecked>([&statement](auto& connection) -> uint64_t {
395 using T = std::decay_t<decltype(connection)>;
396 if constexpr (!std::is_same_v<T, std::monostate>) {
397 auto result = (*connection)(statement);
398 // For INSERT operations, most databases return the ID directly as uint64_t
399 if constexpr (std::is_integral_v<decltype(result)>) {
400 return static_cast<uint64_t>(result);
401 } else {
402 throw std::runtime_error("Unexpected result type from INSERT operation - expected integral type");
403 }
404 }
405 // This should never be reached due to VisitConnection logic
406 throw std::runtime_error("Unreachable: monostate in QueryInsertAndGetId lambda");
407 });
408 } //<! Execute an INSERT statement and return the auto-increment ID.
409
410 const string GetVersion(); //! Return a full version string for the DB schema
411 const string GetVersionMajor() {return fVersionMajor;} //<! fVersionMajor getter
412 const string GetVersionMinor() {return fVersionMinor;} //<! fVersionMinor getter
413 const string GetVersionPoint() {return fVersionPoint;} //<! fVersionPoint getter
414 const string GetValidVersion(); //<! Return a full required version string.
415
416 void PrintServerInfo(); //<! Print Server Information
417
418 private:
420 private:
421
422 Bool_t ValidateConnection(); //!< Checks that given connection parameters result in a valid connection
423 bool StoreDBVersion(); //!< Retrieve database schema version information from database
424
425 // Do not allow compiler to automatically generated these functions
426 QwDatabase(const QwDatabase& rhs); //!< Copy Constructor (not implemented)
427 QwDatabase& operator= (const QwDatabase& rhs); //!< Assignment operator (not implemented)
428// QwDatabase* operator& (); //!< Address-of operator (not implemented)
429// const QwDatabase* operator& () const; //!< Address-of operator (not implemented)
430
431 EQwDBAccessLevel fAccessLevel; //!< Access level of the database instance
432
433 string fDatabase; //!< Name of database to connect to
434 string fDBServer; //!< Name of server carrying DB to connect to
435 string fDBUsername; //!< Name of account to connect to DB server with
436 string fDBPassword; //!< DB account password
437 UInt_t fDBPortNumber; //!< Port number to connect to on server (mysql default port is 3306)
438 Bool_t fValidConnection; //!< True if a valid connection was established using defined connection information
439 Bool_t fDBDebug; //!< True if database debug information should be printed to stdout
440
441 string fVersionMajor; //!< Major version number of current DB schema
442 string fVersionMinor; //!< Minor version number of current DB schema
443 string fVersionPoint; //!< Point version number of current DB schema
444 const string kValidVersionMajor;
445 const string kValidVersionMinor;
446 const string kValidVersionPoint;
447
448 protected:
449 Bool_t fDBInsertMissingKeys; //!< True if missing keys should be inserted into the database automatically
450
451};
ANSI color codes and color management for terminal output.
A logfile class, based on an identical class in the Hermes analyzer.
Basic data types and constants used throughout the Qweak analysis framework.
An options class which parses command line, config file and environment.
A RAII-style scoped database connection.
Definition QwDatabase.h:83
const QwDatabase & operator*() const
Definition QwDatabase.h:104
QwScopedConnection & operator=(const QwScopedConnection &)=delete
const QwDatabase * operator->() const
Definition QwDatabase.h:102
QwDatabase & operator*()
Definition QwDatabase.h:103
bool IsConnected() const
Definition QwDatabase.cc:69
QwDatabase * operator->()
Definition QwDatabase.h:101
QwScopedConnection(QwDatabase *db)
Definition QwDatabase.cc:28
QwDatabase * fDatabase
Definition QwDatabase.h:85
QwScopedConnection(const QwScopedConnection &)=delete
A database interface class.
Definition QwDatabase.h:121
auto VisitConnection(Lambda &&lambda)
Definition QwDatabase.h:187
string fDBUsername
Name of account to connect to DB server with.
Definition QwDatabase.h:435
auto QuerySelect(const Statement &statement)
Definition QwDatabase.h:371
Bool_t AllowsReadAccess()
Definition QwDatabase.h:309
const string kValidVersionPoint
Definition QwDatabase.h:446
Bool_t AllowsWriteAccess()
Definition QwDatabase.h:310
Bool_t ValidateConnection()
Checks that given connection parameters result in a valid connection.
std::variant< std::monostate > QuerySelectReturnType
Definition QwDatabase.h:163
const string GetValidVersion()
void QueryExecute(const Statement &statement)
Definition QwDatabase.h:383
static void DefineOptions(QwOptions &options)
Defines available class options for QwOptions.
bool QueryExists(const Statement &statement)
Definition QwDatabase.h:366
bool StoreDBVersion()
Retrieve database schema version information from database.
const string GetVersion()
QwDatabase(const QwDatabase &rhs)
Copy Constructor (not implemented)
void Disconnect()
Definition QwDatabase.h:313
QwDatabase & operator=(const QwDatabase &rhs)
Assignment operator (not implemented)
const string kValidVersionMinor
Definition QwDatabase.h:445
void QuerySelectForEachResult(const Statement &statement, Lambda &&lambda)
Definition QwDatabase.h:216
Bool_t fDBInsertMissingKeys
True if missing keys should be inserted into the database automatically.
Definition QwDatabase.h:449
uint64_t QueryInsertAndGetId(const InsertStatement &statement)
Definition QwDatabase.h:393
const string GetServerVersion()
Definition QwDatabase.h:338
string fDBServer
Name of server carrying DB to connect to.
Definition QwDatabase.h:434
Bool_t Connect()
Open a connection to the database using the predefined parameters.
string fVersionPoint
Point version number of current DB schema.
Definition QwDatabase.h:443
QwDatabase(const string &major="00", const string &minor="00", const string &point="0000")
Simple constructor.
Definition QwDatabase.cc:78
auto VisitConnectionForSelect(Lambda &&lambda) -> QuerySelectReturnType< Statement >
Definition QwDatabase.h:285
@ kQwDatabaseReadWrite
Definition QwDatabase.h:419
@ kQwDatabaseReadOnly
Definition QwDatabase.h:419
const string kValidVersionMajor
Definition QwDatabase.h:444
QwScopedConnection GetScopedConnection()
Definition QwDatabase.h:335
Bool_t fDBDebug
True if database debug information should be printed to stdout.
Definition QwDatabase.h:439
void PrintServerInfo()
virtual ~QwDatabase()
Destructor.
size_t CountResults(QueryResult &result) const
Definition QwDatabase.h:248
void SetAccessLevel(string accesslevel)
Sets the access level flag based on string labels: "off", "ro", "rw".
string fDatabase
Name of database to connect to.
Definition QwDatabase.h:433
void ForEachResult(QueryResult &result, Lambda &&lambda) const
Definition QwDatabase.h:223
EQwDBAccessLevel fAccessLevel
Access level of the database instance.
Definition QwDatabase.h:431
Bool_t Connected()
Get a scoped connection that automatically disconnects when destroyed.
Definition QwDatabase.h:323
DatabaseConnection fDBConnection
Definition QwDatabase.h:176
size_t QueryCount(const Statement &statement)
Definition QwDatabase.h:348
string fVersionMinor
Minor version number of current DB schema.
Definition QwDatabase.h:442
const string GetVersionMajor()
Return a full version string for the DB schema.
Definition QwDatabase.h:411
UInt_t fDBPortNumber
Port number to connect to on server (mysql default port is 3306)
Definition QwDatabase.h:437
const string GetVersionPoint()
Definition QwDatabase.h:413
string fVersionMajor
Major version number of current DB schema.
Definition QwDatabase.h:441
string fDBPassword
DB account password.
Definition QwDatabase.h:436
bool QuerySelectForFirstResult(const Statement &statement, Lambda &&lambda)
Definition QwDatabase.h:259
std::variant< std::monostate > DatabaseConnection
Definition QwDatabase.h:148
const string GetVersionMinor()
Definition QwDatabase.h:412
Bool_t fValidConnection
True if a valid connection was established using defined connection information.
Definition QwDatabase.h:438
EQwDBType fDBType
Type of database backend to use.
Definition QwDatabase.h:134
size_t QuerySelectCountResults(const Statement &statement)
Definition QwDatabase.h:237
bool ForFirstResult(QueryResult &result, Lambda &&lambda) const
Definition QwDatabase.h:272
void ProcessOptions(QwOptions &options)
Processes the options contained in the QwOptions object.
Command-line and configuration file options processor.
Definition QwOptions.h:141