|
|
|
#ifndef _MYSQL_
|
|
|
|
#define _MYSQL_
|
|
|
|
|
|
|
|
#include <queue>
|
|
|
|
#include <mutex>
|
|
|
|
#include <thread>
|
|
|
|
#include <future>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
#include <tuple>
|
|
|
|
#include "ctime"
|
|
|
|
#include <chrono>
|
|
|
|
|
|
|
|
#include <mysql_driver.h>
|
|
|
|
#include <mysql_connection.h>
|
|
|
|
#include <cppconn/driver.h>
|
|
|
|
#include <cppconn/connection.h>
|
|
|
|
#include <cppconn/statement.h>
|
|
|
|
#include <cppconn/prepared_statement.h>
|
|
|
|
#include <cppconn/resultset.h>
|
|
|
|
|
|
|
|
#define unlimited 0
|
|
|
|
#define reconnectSleep 1000 // in us
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace sql;
|
|
|
|
using namespace mysql;
|
|
|
|
|
|
|
|
namespace marcelb {
|
|
|
|
namespace mysql {
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#define MYSQL_PERIODIC_INTERNAL_TIME 5000
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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<typename... Types>
|
|
|
|
class MySQL_Res : public vector<tuple<Types...>> {
|
|
|
|
public:
|
|
|
|
bool have_result = false;
|
|
|
|
uint16_t affected = 0;
|
|
|
|
uint16_t rows = 0;
|
|
|
|
uint16_t columns = sizeof...(Types);
|
|
|
|
vector<string> columns_name;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Type conversion functions
|
|
|
|
*/
|
|
|
|
template<typename T>
|
|
|
|
T getValue(ResultSet* res, int column);
|
|
|
|
template<>
|
|
|
|
inline int getValue<int>(ResultSet* res, int column) {
|
|
|
|
return res->getInt(column);
|
|
|
|
}
|
|
|
|
template<>
|
|
|
|
inline uint32_t getValue<uint32_t>(ResultSet* res, int column) {
|
|
|
|
return res->getUInt(column);
|
|
|
|
}
|
|
|
|
template<>
|
|
|
|
inline int64_t getValue<int64_t>(ResultSet* res, int column) {
|
|
|
|
return res->getInt64(column);
|
|
|
|
}
|
|
|
|
template<>
|
|
|
|
inline uint64_t getValue<uint64_t>(ResultSet* res, int column) {
|
|
|
|
return res->getUInt64(column);
|
|
|
|
}
|
|
|
|
template<>
|
|
|
|
inline float getValue<float>(ResultSet* res, int column) {
|
|
|
|
return res->getDouble(column);
|
|
|
|
}
|
|
|
|
template<>
|
|
|
|
inline double getValue<double>(ResultSet* res, int column) {
|
|
|
|
return res->getDouble(column);
|
|
|
|
}
|
|
|
|
template<>
|
|
|
|
inline string getValue<string>(ResultSet* res, int column) {
|
|
|
|
return res->getString(column);
|
|
|
|
}
|
|
|
|
template<>
|
|
|
|
inline bool getValue<bool>(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*> connection_pool;
|
|
|
|
string path, username, password, database;
|
|
|
|
uint32_t pool_size;
|
|
|
|
bool run_tloop = true;
|
|
|
|
future<void> tloop_future;
|
|
|
|
time_loop_type tloop_type;
|
|
|
|
time_t last_loop_time;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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<typename... Types, size_t... Is>
|
|
|
|
static tuple<Types...> getRow(sql::ResultSet* res, index_sequence<Is...>) {
|
|
|
|
return make_tuple(getValue<Types>(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:
|
|
|
|
function<void(const string&)> on_error;
|
|
|
|
uint32_t connect_trys = 3;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Execute the SQL statement
|
|
|
|
*/
|
|
|
|
template<typename... Types>
|
|
|
|
MySQL_Res<Types...> exec(const string& sql_q) {
|
|
|
|
Connection* connection = occupy_connection();
|
|
|
|
MySQL_Res<Types...> 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<Types...>(res, make_index_sequence<sizeof...(Types)>{}));
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|