#include "../lib/mysql.hpp" sqlQA& sqlQA::select(const string _columns) { if (_columns != "*") { parse_columns(_columns); } isSelect = true; cmd += "SELECT " + _columns + " "; return *this; } sqlQA& sqlQA::from(const string _table) { table = _table; cmd += "FROM " + _table + " "; return *this; } sqlQA& sqlQA::where(const string _condition) { cmd += "WHERE " + _condition + " "; return *this; } sqlQA& sqlQA::limit(const uint _limit) { cmd += "LIMIT " + to_string(_limit) + " "; return *this; } sqlQA& sqlQA::insertInTo(const string _tablename, const string _columns) { isUpdate = true; cmd += "INSERT INTO " + _tablename; if (_columns.empty()) { cmd += " "; } else { cmd += " (" + _columns + ") "; } return *this; } sqlQA& sqlQA::values(const string _values) { cmd += "VALUES (" + _values + ") "; return *this; } sqlQA& sqlQA::update(const string _table) { isUpdate = true; cmd += "UPDATE " + _table + " "; return *this; } sqlQA& sqlQA::set(const string _column_value_pairs) { cmd += "SET " + _column_value_pairs + " "; return *this; } sqlQA& sqlQA::deleteFrom(const string _table) { isUpdate = true; cmd += "DELETE FROM " + _table + " "; return *this; } void sqlQA::print(bool withDetail) { cout << "============================================" << endl; for (auto i : result) { for (auto j: i.second) { cout << i.first << " : " << j << endl; } cout << "--------------------------------------------" << endl; } if (withDetail) { cout << "-----------------DETAILS--------------------" << endl; cout << "Is executed: " << (executed ? "true" : "false") << endl; cout << "Update catch: " << updateCatch << endl; cout << "Num of rows: " << num_rows << endl; cout << "Num of columns: " << num_columns << endl; } cout << "============================================" << endl; } void sqlQA::parse_columns(const string _columns) { istringstream iss(_columns); string columnName; while (getline(iss, columnName, ',')) { size_t startPos = columnName.find_first_not_of(" "); size_t endPos = columnName.find_last_not_of(" "); if (startPos != string::npos && endPos != string::npos) { columns.push_back(columnName.substr(startPos, endPos - startPos + 1)); } } } mySQL::mySQL(const string _path, const string _username, const string _password, const string _db, const uint _available) { path = _path; username = _username; password = _password; db = _db; available = _available > 0 ? _available : 1; drv = get_mysql_driver_instance(); bot = async(launch::async, [&](){ while (runBot) { sleep(1); while (available>con.size() && runBot) { try { Connection* new_con_ptr = create_con(); if (!db.empty()) { if (open_one(new_con_ptr)) { throw string("[ERROR] Unable to open database " + db); } } io.lock(); con.push_back(new_con_ptr); io.unlock(); } catch (const SQLException except) { cout << except.what() << endl; } catch (const string except) { cout << except << endl; } } for (int i=0; i<con.size() && runBot; i++) { if (!con[i]->isValid()) { io.lock(); con.erase(con.begin()+i); io.unlock(); i--; } } } return; }); } Connection* mySQL::create_con() { uint trys = 0; bool status = true; Connection* new_con = NULL; while (reconTrys == unlimited ? status : (trys <= reconTrys && status)) { try { Connection* con_can = drv->connect(path, username, password); status = !con_can->isValid(); if (!status) { new_con = con_can; } else if (!con_can->isClosed()) { disconnect_one(con_can); } } catch (const SQLException &error) { cout << error.what() << endl; usleep(reconnectSleep); reconTrys == unlimited ? trys : trys++; } } return new_con; } bool mySQL::disconnect() { io.lock(); bool status = true; for (uint i=0; i<con.size(); i++) { status = disconnect_one(con[i]) ; } io.unlock(); return status; } bool mySQL::disconnect_one(Connection* con_ptr) { bool status = !con_ptr->isClosed(); if (status) { try { con_ptr->close(); status = !con_ptr->isClosed(); } catch (const SQLException &error) { cout << error.what() << endl; status = true; } } else { status = false; // već je zatvorena } delete con_ptr; return status; } bool mySQL::open_one(Connection* con_ptr) { bool status = true; // ako true greška je uint trys = 0; while (reconTrys == unlimited ? status : (trys <= reconTrys && status)) { try { if (con_ptr->isValid()) { con_ptr->setSchema(db); status = false; } else { break; } } catch (const SQLException &error) { cout << error.what() << endl; usleep(reconnectSleep); reconTrys == unlimited ? trys : trys++; } } return status; } /** * Broj pokušaja usljed povezivanja s bazom od 1 do unlimited; */ void mySQL::reconnectTrys(const uint _trys) { io.lock(); reconTrys = _trys; io.unlock(); } void mySQL::exec(sqlQA &sql_qa) { Connection* con_ptr = shift_con(); try { vector<string> columns = sql_qa.columns; if (columns.empty() && !sql_qa.table.empty()) { getColumns(sql_qa.table, columns, con_ptr); } Statement *stmt; stmt = con_ptr->createStatement(); if (sql_qa.isSelect) { ResultSet *res = stmt->executeQuery(sql_qa.cmd); sql_qa.executed = true; uint num_raw_columns = 0; while (res->next()) { for (uint i=0; i<columns.size(); i++) { sql_qa.result[columns[i]].push_back(res->getString(columns[i])); num_raw_columns++; } } res->close(); delete res; sql_qa.num_columns = columns.size(); sql_qa.num_rows = num_raw_columns/columns.size(); } if (sql_qa.isUpdate) { sql_qa.updateCatch = stmt->executeUpdate(sql_qa.cmd); sql_qa.executed = true; } else { sql_qa.executed = stmt->execute(sql_qa.cmd); } stmt->close(); delete stmt; disconnect_one(con_ptr); } catch (const SQLException &error) { cout << error.what() << endl; sql_qa.executed = false; } catch (const string error) { throw error; } } void mySQL::getColumns(const string _table, vector<string> &_columns, Connection *ptr_con) { Statement *stmt; stmt = ptr_con->createStatement(); ResultSet *columnsRes = stmt->executeQuery("SHOW COLUMNS from " + _table); while (columnsRes->next()) { _columns.push_back(columnsRes->getString("Field")); } columnsRes->close(); stmt->close(); delete columnsRes; delete stmt; } Connection* mySQL::shift_con() { while (true) { while(con.size()) { io.lock(); Connection* con_ptr = con[0]; con.pop_front(); if (con_ptr->isValid()) { io.unlock(); return con_ptr; } io.unlock(); } usleep(1000); } } mySQL::~mySQL() { runBot = false; bot.get(); disconnect(); }