#ifndef _MYSQL_ #define _MYSQL_ #include #include #include #include #include #include #include #include "ctime" #include #include #include #include #include #include #include #define unlimited 0 #define reconnectSleep 10000 // in us using namespace std; using namespace sql; using namespace mysql; namespace marcelb { namespace mysql { /** * */ #define MYSQL_PERIODIC_INTERNAL_TIME 1000 /** * An enumeration of how periodic functions will be run * internal - run periodic_maintenance() i new thread * external - expects periodic_maintenance() to be run periodically outside the library * */ enum class time_loop_type { internal, external }; /** * A class for creating sql responses */ template class MySQL_Res : public vector> { public: bool have_result = false; uint16_t affected = 0; uint16_t rows = 0; uint16_t columns = sizeof...(Types); vector columns_name; }; /** * Type conversion functions */ template T getValue(ResultSet* res, int column); template<> inline int getValue(ResultSet* res, int column) { return res->getInt(column); } template<> inline uint32_t getValue(ResultSet* res, int column) { return res->getUInt(column); } template<> inline int64_t getValue(ResultSet* res, int column) { return res->getInt64(column); } template<> inline uint64_t getValue(ResultSet* res, int column) { return res->getUInt64(column); } template<> inline float getValue(ResultSet* res, int column) { return res->getDouble(column); } template<> inline double getValue(ResultSet* res, int column) { return res->getDouble(column); } template<> inline string getValue(ResultSet* res, int column) { return res->getString(column); } template<> inline bool getValue(ResultSet* res, int column) { return res->getBoolean(column); } // implementiraj neku c++ kompatibilnu pretvorbu za timestampe, time, date datetime itd. class MySQL { mutex io; condition_variable condition; MySQL_Driver *drv; queue connection_pool; string path, username, password, database; uint32_t pool_size; uint32_t connect_trys = 3; bool run_tloop = true; future tloop_future; time_loop_type tloop_type; time_t last_loop_time = time(nullptr); function on_error; /** * Open one database server connection */ Connection* create_connection(); /** * Close one database connection */ bool disconnect_connection(Connection* connection); /** * Take an pool_size database connection */ Connection* occupy_connection(); /** * Free an database connection */ void release_connection(Connection* connection); /** * Function parses a parameterized row */ template static tuple getRow(sql::ResultSet* res, index_sequence) { return make_tuple(getValue(res, Is + 1)...); } /** * Connect all connections to server */ void connect_pool(); /** * Disconnect all connections to server */ void disconnect_pool(); /** * Internal tloop periodic */ void _tloop(); public: /** * MySQL constructor, * receive the path to the mysql server, * username, password, database name, * and number of active connections (optional) */ MySQL(const string _path, const string _username, const string _password, const string _db, const uint32_t _available = 1, const time_loop_type _engine_type = time_loop_type::internal); /** * Define the maximum number of attempts to * reconnect to the server */ void set_connect_trys(const uint32_t _trys); /** * Set callback on error */ void set_on_error(function _on_error); /** * Execute the SQL statement */ template MySQL_Res exec(const string& sql_q) { Connection* connection = occupy_connection(); MySQL_Res result; try { Statement *stmt; stmt = connection->createStatement(); result.have_result = stmt->execute(sql_q); if (result.have_result) { ResultSet* res = stmt->getResultSet(); result.rows = res->rowsCount(); ResultSetMetaData *metaData = res->getMetaData(); int columnCount = metaData->getColumnCount(); for (int i = 1; i <= columnCount; ++i) { result.columns_name.push_back(metaData->getColumnName(i)); } while (res->next()) { result.push_back(MySQL::getRow(res, make_index_sequence{})); } res->close(); delete res; } else { result.affected = stmt->getUpdateCount(); } stmt->close(); delete stmt; release_connection(connection); } catch (sql::SQLException& e) { throw runtime_error(e.what()); // std::cerr << "SQLState: " << e.getSQLState() << std::endl; // std::cerr << "Error code: " << e.getErrorCode() << std::endl; } return result; } /** * If you are using an external periodic motor, * please call this function in it for proper operation at a certain time interval. * You can use the default MYSQL_PERIODIC_INTERNAL_TIME */ void tloop(); /** * Destruktor * close all connections */ ~MySQL(); }; } } #endif