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.
An options class which parses command line, config file and environment.
A logfile class, based on an identical class in the Hermes analyzer.
Basic data types and constants used throughout the Qweak analysis framework.
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