/* * Copyright (c) 2010-2012 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifdef WIN32 #include #endif #include "mysql.h" #include #include #include DatabaseMySQL::DatabaseMySQL() : m_running(false) { if(!mysql_init(&m_mysqlHandle)) g_logger.fatal("Failed to initialize MySQL connection handle."); my_bool reconnect = true; mysql_options(&m_mysqlHandle, MYSQL_OPT_RECONNECT, &reconnect); } DatabaseMySQL::~DatabaseMySQL() { mysql_close(&m_mysqlHandle); } void DatabaseMySQL::connect(const std::string& host, const std::string& user, const std::string& pass, const std::string& db, uint16_t port, const std::string& unix_socket) { if(!mysql_real_connect(&m_mysqlHandle, host.c_str(), user.c_str(), pass.c_str(), db.c_str(), port, unix_socket.empty() ? NULL : unix_socket.c_str(), 0)) { g_logger.error(stdext::format("Failed to connect to database. MYSQL ERROR: %s", mysql_error(&m_mysqlHandle))); } } bool DatabaseMySQL::handleError() { unsigned int error = mysql_errno(&m_mysqlHandle); g_logger.error(stdext::format("MYSQL error code = %d, message: %s", error, mysql_error(&m_mysqlHandle))); if(error == CR_SOCKET_CREATE_ERROR || error == CR_CONNECTION_ERROR || error == CR_CONN_HOST_ERROR || error == CR_IPSOCK_ERROR || error == CR_UNKNOWN_HOST || error == CR_SERVER_GONE_ERROR || error == CR_SERVER_LOST || error == CR_SERVER_HANDSHAKE_ERR) { g_logger.error("MYSQL connection lost, trying to reconnect..."); //int64_t startTime = g_clock.millis(); /*while(true) { bool connected = (mysql_ping(&m_mysqlHandle) == 0); uint32_t diffTime = (mTime() - startTime); if(connected) { g_logger.info(stdext::format("MySQL reconneted in %d ms", diffTime)); return true; } mSleep(100); }*/ } return false; } bool DatabaseMySQL::beginTransaction() { return executeQuery("BEGIN"); } bool DatabaseMySQL::rollback() { if(mysql_rollback(&m_mysqlHandle) != 0) { g_logger.error(mysql_error(&m_mysqlHandle)); return false; } return true; } bool DatabaseMySQL::commit() { if(mysql_commit(&m_mysqlHandle) != 0) { g_logger.error(mysql_error(&m_mysqlHandle)); return false; } return true; } bool DatabaseMySQL::internalExecuteQuery(const std::string &query) { while(mysql_real_query(&m_mysqlHandle, query.c_str(), query.length()) != 0) { if(!handleError()) { return false; } } return true; } bool DatabaseMySQL::executeQuery(const std::string &query) { //LOG_ONDELAY(500); if(internalExecuteQuery(query)) { MYSQL_RES *m_res = mysql_store_result(&m_mysqlHandle); if(m_res) { mysql_free_result(m_res); } else if(mysql_errno(&m_mysqlHandle) != 0) { handleError(); } return true; } return false; } DBResultPtr DatabaseMySQL::storeQuery(const std::string &query) { //LOG_ONDELAY(500); while(internalExecuteQuery(query)) { MYSQL_RES *m_res = mysql_store_result(&m_mysqlHandle); if(m_res) { DBResultPtr res = DBResultPtr(new DBResult(m_res)); if(res->next()) { return res; } else { //delete res; break; } } else if(mysql_errno(&m_mysqlHandle) != 0) { if(!handleError()) { break; } } //mSleep(10); } return NULL; } uint64_t DatabaseMySQL::getLastInsertedRowID() { return (uint64_t)mysql_insert_id(&m_mysqlHandle); } std::string DatabaseMySQL::escapeString(const std::string &s) { return escapeBlob( s.c_str(), s.length() ); } std::string DatabaseMySQL::escapeBlob(const char* s, uint32_t length) { if(!s) return std::string("''"); char* output = new char[length * 2 + 1]; mysql_real_escape_string(&m_mysqlHandle, output, s, length); std::string r = "'"; r += output; r += "'"; delete[] output; return r; } void DatabaseMySQL::freeResult(DBResult* res) { delete res; } DBResult::DBResult(MYSQL_RES* res) { m_res = res; m_listNames.clear(); MYSQL_FIELD* field; int32_t i = 0; while((field = mysql_fetch_field(m_res))) { m_listNames[field->name] = i; i++; } } DBResult::~DBResult() { mysql_free_result(m_res); } int32_t DBResult::getDataInt(const std::string &s) { ListNames::iterator it = m_listNames.find(s); if(it != m_listNames.end() ) { if(m_row[it->second] == NULL) { return 0; } else { return atoi(m_row[it->second]); } } g_logger.error(stdext::format("error during getDataInt(%s).", s)); return 0; } int64_t DBResult::getDataLong(const std::string &s) { ListNames::iterator it = m_listNames.find(s); if(it != m_listNames.end()) { if(m_row[it->second] == NULL) { return 0; } else { return atoll(m_row[it->second]); } } g_logger.error(stdext::format("error during getDataLong(%s).", s)); return 0; } std::string DBResult::getDataString(const std::string &s) { ListNames::iterator it = m_listNames.find(s); if(it != m_listNames.end() ) { if(m_row[it->second] == NULL) return std::string(""); else return std::string(m_row[it->second]); } g_logger.error(stdext::format("error during getDataString(%s).", s)); return std::string(""); } const char* DBResult::getDataStream(const std::string &s, unsigned long &size) { ListNames::iterator it = m_listNames.find(s); if(it != m_listNames.end() ) { if(m_row[it->second] == NULL) { size = 0; return NULL; } else { size = mysql_fetch_lengths(m_res)[it->second]; return m_row[it->second]; } } g_logger.error(stdext::format("error during getDataStream(%s).", s)); size = 0; return NULL; } bool DBResult::next() { m_row = mysql_fetch_row(m_res); return m_row != NULL; }