diff --git a/GeoModelIO/GeoModelDBManager/GeoModelDBManager/GMDBManager.h b/GeoModelIO/GeoModelDBManager/GeoModelDBManager/GMDBManager.h index 3214b428fbf354a9701fd9d2cf9d4496c664093b..6c4733c8326d55a8df0e70b29533c2de189c4d96 100644 --- a/GeoModelIO/GeoModelDBManager/GeoModelDBManager/GMDBManager.h +++ b/GeoModelIO/GeoModelDBManager/GeoModelDBManager/GMDBManager.h @@ -1,12 +1,11 @@ // author: Riccardo.Maria.Bianchi@cern.ch - 2017 -// major updates: Aug 2018 +// major updates: +// - Aug 2018, R.M.Bianchi +// - Nov 2020, R.M.Bianchi #ifndef GMDBManager_H #define GMDBManager_H -// include SQLite -#include <sqlite3.h> - // include C++ #include <iostream> #include <unordered_map> @@ -14,6 +13,7 @@ #include <string> #include <typeindex> // std::type_index, needs C++11 + /** * \class GMDBManager * @@ -169,6 +169,7 @@ public: * @note The 'suffix' parameter is optional. If not provided, the records will be saved in the default table. */ bool addListOfPublishedAlignableTransforms(const std::vector<std::vector<std::string>> &records, std::string suffix = ""); + /** * @brief Save the list of 'published' GeoVFullPhysVol nodes to the DB. * @details The method gets a list of records and stores them in the default table 'PublishedFullPhysVols". @@ -237,10 +238,6 @@ private: std::string getTableNameFromNodeType(const std::string &nodeType); - sqlite3_stmt* selectAllFromTable(std::string tableName) const; - sqlite3_stmt* selectAllFromTableSortBy(std::string tableName, std::string sortColumn="") const; - sqlite3_stmt* selectAllFromTableChildrenPositions() const; - void storeTableColumnNames(std::vector<std::string> input); std::vector<std::string> getTableColumnNames(const std::string &tableName); @@ -251,20 +248,11 @@ private: bool storeRootVolume(const unsigned int &id, const std::string &nodeType); -// void showError(const QSqlError &err) const; - std::string m_dbpath; -// QSqlDatabase m_db; - /// Pointer to SQLite connection - sqlite3* m_dbSqlite; - /// Variable to store error messages from SQLite - char *m_SQLiteErrMsg; + bool m_dbIsOK; - - bool m_dbIsOK; - - bool m_debug; + bool m_debug; std::unordered_map<std::string, std::vector<std::string>> m_tableNames; /// stores the column names for each table std::unordered_map<std::string, std::string> m_childType_tableName; @@ -274,6 +262,12 @@ private: std::unordered_map<unsigned int, std::string> m_cache_tableId_nodeType; /// cache for tableID-->nodeType std::unordered_map<std::string, std::string> m_cache_nodeType_tableName; /// cache for nodeType-->tableName std::unordered_map<std::string, unsigned int> m_cache_nodeType_tableID; /// cache for nodeType-->tableID + +protected: + class Imp; + Imp * m_d; + }; + #endif // GMDBManager_H diff --git a/GeoModelIO/GeoModelDBManager/src/GMDBManager.cpp b/GeoModelIO/GeoModelDBManager/src/GMDBManager.cpp index f0256010d77b74ee84b15546713c1bba7e28563f..21651a252935a9b9a2b56f39e691b009f2dbc4cd 100644 --- a/GeoModelIO/GeoModelDBManager/src/GMDBManager.cpp +++ b/GeoModelIO/GeoModelDBManager/src/GMDBManager.cpp @@ -17,6 +17,9 @@ #define FMT_HEADER_ONLY 1 // to use 'fmt' header-only #include "fmt/format.h" +// include SQLite +#include <sqlite3.h> + // C++ includes #include <stdlib.h> /* exit, EXIT_FAILURE */ #include <sstream> @@ -58,7 +61,29 @@ std::string joinVectorStrings(std::vector<std::string> vec, std::string sep="") } -GMDBManager::GMDBManager(const std::string &path) : m_dbpath(path), m_dbSqlite(nullptr), m_SQLiteErrMsg(0), m_dbIsOK(false), m_debug(false) + +class GMDBManager::Imp { +public: + // constructor + Imp (GMDBManager* dbm) + : theManager(dbm), m_dbSqlite(nullptr), m_SQLiteErrMsg(0) {} + + // The class + GMDBManager* theManager; + + // Pointer to SQLite connection + sqlite3* m_dbSqlite; + + /// Variable to store error messages from SQLite + char *m_SQLiteErrMsg; + + sqlite3_stmt* selectAllFromTable(std::string tableName) const; + sqlite3_stmt* selectAllFromTableSortBy(std::string tableName, std::string sortColumn="") const; + sqlite3_stmt* selectAllFromTableChildrenPositions() const; + +}; + +GMDBManager::GMDBManager(const std::string &path) : m_dbpath(path), m_dbIsOK(false), m_debug(false), m_d(new Imp(this)) { // Check if the user asked for running in serial or multi-threading mode if ( "" != getEnvVar("GEOMODEL_ENV_IO_DBMANAGER_DEBUG")) { @@ -70,14 +95,14 @@ GMDBManager::GMDBManager(const std::string &path) : m_dbpath(path), m_dbSqlite(n // FIXME: TODO: we should check the existence of the file, otherwise SQLite will create a new file from scratch // Save the connection result - int exit = sqlite3_open(path.c_str(), &m_dbSqlite); + int exit = sqlite3_open(path.c_str(), &m_d->m_dbSqlite); // Test if there was an error if (exit == SQLITE_OK) { std::cout << "The Geometry Database '"<< path << "' has been opened successfully!" << std::endl; m_dbIsOK = true; } else { - std::cout << "DB Open Error: " << sqlite3_errmsg(m_dbSqlite) << std::endl; + std::cout << "DB Open Error: " << sqlite3_errmsg(m_d->m_dbSqlite) << std::endl; m_dbIsOK = false; } @@ -95,8 +120,8 @@ GMDBManager::GMDBManager(const std::string &path) : m_dbpath(path), m_dbSqlite(n GMDBManager::~GMDBManager() { - sqlite3_close(m_dbSqlite); - m_dbSqlite = nullptr; + sqlite3_close(m_d->m_dbSqlite); + m_d->m_dbSqlite = nullptr; } @@ -220,10 +245,10 @@ std::vector<std::vector<std::string>> GMDBManager::getTableRecords(std::string t // get the query statetement ready to be executed sqlite3_stmt* stmt = nullptr; if ("ChildrenPositions" == tableName) { - stmt = selectAllFromTableChildrenPositions(); + stmt = m_d->selectAllFromTableChildrenPositions(); } else { - stmt = selectAllFromTable(tableName); + stmt = m_d->selectAllFromTable(tableName); } // execute the query and loop over all rows and all columuns if ( stmt ) @@ -247,7 +272,7 @@ std::vector<std::vector<std::string>> GMDBManager::getTableRecords(std::string t if ( res == SQLITE_DONE || res==SQLITE_ERROR) { if (res == SQLITE_ERROR) { - std::string errmsg(sqlite3_errmsg(m_dbSqlite)); + std::string errmsg(sqlite3_errmsg(m_d->m_dbSqlite)); sqlite3_finalize(stmt); throw errmsg; } @@ -592,15 +617,15 @@ void GMDBManager::addDBversion(std::string version) sqlite3_stmt * st = nullptr; int rc = -1; std::string sql = "INSERT INTO dbversion(version) VALUES(?)"; - rc = sqlite3_prepare_v2( m_dbSqlite, sql.c_str(), -1, &st, NULL); + rc = sqlite3_prepare_v2( m_d->m_dbSqlite, sql.c_str(), -1, &st, NULL); if (rc != SQLITE_OK) { - printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_dbSqlite) ); + printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_d->m_dbSqlite) ); exit(EXIT_FAILURE); } rc = sqlite3_bind_text(st, 1, version.c_str(), version.length(), SQLITE_TRANSIENT); rc = sqlite3_step( st ); if (rc != SQLITE_DONE) { - printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_dbSqlite) ); + printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_d->m_dbSqlite) ); exit(EXIT_FAILURE); } // finalize @@ -610,7 +635,7 @@ void GMDBManager::addDBversion(std::string version) bool GMDBManager::checkIsDBOpen() const { - if(m_dbSqlite != nullptr) { + if(m_d->m_dbSqlite != nullptr) { return true; } else { std::cout << "ERROR! The SQLite DB is not accessible! Exiting..." << std::endl; @@ -645,9 +670,9 @@ std::vector<std::string> GMDBManager::getItemFromTableName(std::string tableName // prepare the query sqlite3_stmt * stmt = nullptr; int rc = -1; - rc = sqlite3_prepare_v2( m_dbSqlite, sql.c_str(), -1, &stmt, NULL); + rc = sqlite3_prepare_v2( m_d->m_dbSqlite, sql.c_str(), -1, &stmt, NULL); if (rc != SQLITE_OK) { - printf( "[SQLite ERR] 'prepare' (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_dbSqlite) ); + printf( "[SQLite ERR] 'prepare' (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_d->m_dbSqlite) ); exit(EXIT_FAILURE); } // bind the parameters @@ -671,7 +696,7 @@ std::vector<std::string> GMDBManager::getItemFromTableName(std::string tableName if ( res == SQLITE_DONE || res==SQLITE_ERROR) { if (res == SQLITE_ERROR) { - std::string errmsg(sqlite3_errmsg(m_dbSqlite)); + std::string errmsg(sqlite3_errmsg(m_d->m_dbSqlite)); sqlite3_finalize(stmt); throw errmsg; } @@ -681,7 +706,7 @@ std::vector<std::string> GMDBManager::getItemFromTableName(std::string tableName } // TODO: do we need that error check here?? // if (rc != SQLITE_DONE) { -// printf( "[SQLite ERR] 'step' (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_dbSqlite) ); +// printf( "[SQLite ERR] 'step' (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_d->m_dbSqlite) ); //// exit(EXIT_FAILURE); // } // finalize @@ -730,9 +755,9 @@ int GMDBManager::loadGeoNodeTypesAndBuildCache() std::string nodeType = ""; std::string tableName = ""; // prepare the query - rc = sqlite3_prepare_v2( m_dbSqlite, sql.c_str(), -1, &st, NULL); + rc = sqlite3_prepare_v2( m_d->m_dbSqlite, sql.c_str(), -1, &st, NULL); if (rc != SQLITE_OK) { - printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_dbSqlite) ); + printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_d->m_dbSqlite) ); exit(EXIT_FAILURE); } // execute the statement until all selected records are processed @@ -749,7 +774,7 @@ int GMDBManager::loadGeoNodeTypesAndBuildCache() m_cache_nodeType_tableID.insert( std::pair<std::string, unsigned int>(nodeType, id)); } if (rc != SQLITE_DONE) { - std::string errmsg(sqlite3_errmsg(m_dbSqlite)); + std::string errmsg(sqlite3_errmsg(m_d->m_dbSqlite)); sqlite3_finalize(st); throw errmsg; } @@ -781,15 +806,15 @@ std::unordered_map<std::string, unsigned int> GMDBManager::getAll_NodeTypesTable -sqlite3_stmt* GMDBManager::selectAllFromTable(std::string tableName) const +sqlite3_stmt* GMDBManager::Imp::selectAllFromTable(std::string tableName) const { return selectAllFromTableSortBy(tableName, "id"); } -sqlite3_stmt* GMDBManager::selectAllFromTableSortBy(std::string tableName, std::string sortColumn) const +sqlite3_stmt* GMDBManager::Imp::selectAllFromTableSortBy(std::string tableName, std::string sortColumn) const { - checkIsDBOpen(); + theManager->checkIsDBOpen(); if ("" == sortColumn || 0 == sortColumn.size()) { sortColumn = "id"; } @@ -807,9 +832,9 @@ sqlite3_stmt* GMDBManager::selectAllFromTableSortBy(std::string tableName, std:: } -sqlite3_stmt* GMDBManager::selectAllFromTableChildrenPositions() const +sqlite3_stmt* GMDBManager::Imp::selectAllFromTableChildrenPositions() const { - checkIsDBOpen(); + theManager->checkIsDBOpen(); sqlite3_stmt * st = nullptr; int rc = -1; //set the SQL query string @@ -856,9 +881,9 @@ void GMDBManager::getAllDBTables() std::string queryStr = "SELECT name FROM sqlite_master WHERE type ='table' AND name NOT LIKE 'sqlite_%';"; // prepare the query with the query string sqlite3_stmt *stmt; - int rc = sqlite3_prepare_v2(m_dbSqlite, queryStr.c_str(), -1, &stmt, NULL); + int rc = sqlite3_prepare_v2(m_d->m_dbSqlite, queryStr.c_str(), -1, &stmt, NULL); if (rc != SQLITE_OK) { - throw std::string(sqlite3_errmsg(m_dbSqlite)); + throw std::string(sqlite3_errmsg(m_d->m_dbSqlite)); } // execute the statement until all selected records are processed while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { @@ -867,7 +892,7 @@ void GMDBManager::getAllDBTables() tables.push_back(tableName); } if (rc != SQLITE_DONE) { - std::string errmsg(sqlite3_errmsg(m_dbSqlite)); + std::string errmsg(sqlite3_errmsg(m_d->m_dbSqlite)); sqlite3_finalize(stmt); throw errmsg; } @@ -1211,13 +1236,13 @@ int GMDBManager::execQuery(std::string queryStr) if(m_debug) std::cout << "queryStr to execute: " << queryStr << std::endl; // debug checkIsDBOpen(); int result = -1; - if( (result = sqlite3_exec(m_dbSqlite, queryStr.c_str(), NULL, 0, &m_SQLiteErrMsg)) ) + if( (result = sqlite3_exec(m_d->m_dbSqlite, queryStr.c_str(), NULL, 0, &m_d->m_SQLiteErrMsg)) ) { printf( "[ERR] : \t> CMD: %s , Error: %d\n" , queryStr.c_str() , result ); - if ( m_SQLiteErrMsg ) + if ( m_d->m_SQLiteErrMsg ) { - printf( "[ERR] : Error msg: %s\n", m_SQLiteErrMsg ); - sqlite3_free(m_SQLiteErrMsg); + printf( "[ERR] : Error msg: %s\n", m_d->m_SQLiteErrMsg ); + sqlite3_free(m_d->m_SQLiteErrMsg); } } return result; @@ -1249,9 +1274,9 @@ void GMDBManager::storeNodeType(std::string nodeType, std::string tableName) int rc = -1; // preparing the SQL query std::string sql = "INSERT INTO GeoNodesTypes(nodeType, tableName) VALUES(?, ?)"; - rc = sqlite3_prepare_v2( m_dbSqlite, sql.c_str(), -1, &st, NULL); + rc = sqlite3_prepare_v2( m_d->m_dbSqlite, sql.c_str(), -1, &st, NULL); if (rc != SQLITE_OK) { - printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_dbSqlite) ); + printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_d->m_dbSqlite) ); exit(EXIT_FAILURE); } if(m_debug) std::cout << "storeNodeType - Query string:" << sql << std::endl; // debug @@ -1261,7 +1286,7 @@ void GMDBManager::storeNodeType(std::string nodeType, std::string tableName) // execute the query rc = sqlite3_step( st ); if (rc != SQLITE_DONE) { - printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_dbSqlite) ); + printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_d->m_dbSqlite) ); exit(EXIT_FAILURE); } // finalize @@ -1314,9 +1339,9 @@ bool GMDBManager::storeRootVolume(const unsigned int &id, const std::string &nod // preparing the SQL query sqlite3_stmt * st = nullptr; int rc = -1; - rc = sqlite3_prepare_v2( m_dbSqlite, sql.c_str(), -1, &st, NULL); + rc = sqlite3_prepare_v2( m_d->m_dbSqlite, sql.c_str(), -1, &st, NULL); if (rc != SQLITE_OK) { - printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_dbSqlite) ); // TODO: add __func__ to all error messages, as I did here + printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_d->m_dbSqlite) ); // TODO: add __func__ to all error messages, as I did here exit(EXIT_FAILURE); } if(m_debug) std::cout << "Query string:" << sql << std::endl; // debug @@ -1326,7 +1351,7 @@ bool GMDBManager::storeRootVolume(const unsigned int &id, const std::string &nod // execute the query rc = sqlite3_step( st ); if (rc != SQLITE_DONE) { - printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_dbSqlite) ); + printf( "[SQLite ERR] (%s) : Error msg: %s\n", __func__, sqlite3_errmsg(m_d->m_dbSqlite) ); exit(EXIT_FAILURE); } // finalize @@ -1343,7 +1368,7 @@ bool GMDBManager::storeRootVolume(const unsigned int &id, const std::string &nod std::vector<std::string> GMDBManager::getRootPhysVol() { // get the ID of the ROOT vol from the table "RootVolume" - sqlite3_stmt* stmt = selectAllFromTable("RootVolume"); + sqlite3_stmt* stmt = m_d->selectAllFromTable("RootVolume"); // declare the data we want to fetch unsigned int id; unsigned int typeId; @@ -1356,7 +1381,7 @@ std::vector<std::string> GMDBManager::getRootPhysVol() // TODO: fill a cache } if (rc != SQLITE_DONE) { - std::string errmsg(sqlite3_errmsg(m_dbSqlite)); + std::string errmsg(sqlite3_errmsg(m_d->m_dbSqlite)); sqlite3_finalize(stmt); throw errmsg; }