ddnet/src/engine/server/databases/mysql.cpp

271 lines
5.9 KiB
C++
Raw Normal View History

2020-07-04 08:13:21 +00:00
#include "mysql.h"
#if defined(CONF_SQL)
2020-07-04 08:13:21 +00:00
#include <cppconn/driver.h>
#endif
lock CMysqlConnection::m_SqlDriverLock;
2020-07-04 08:13:21 +00:00
CMysqlConnection::CMysqlConnection(
const char *pDatabase,
const char *pPrefix,
const char *pUser,
const char *pPass,
const char *pIp,
int Port,
bool Setup) :
IDbConnection(pPrefix),
#if defined(CONF_SQL)
m_NewQuery(false),
m_Locked(false),
#endif
2020-07-04 08:13:21 +00:00
m_Port(Port),
m_Setup(Setup),
m_InUse(false)
{
str_copy(m_aDatabase, pDatabase, sizeof(m_aDatabase));
str_copy(m_aUser, pUser, sizeof(m_aUser));
str_copy(m_aPass, pPass, sizeof(m_aPass));
str_copy(m_aIp, pIp, sizeof(m_aIp));
#if not defined(CONF_SQL)
dbg_msg("sql", "Adding MySQL server failed due to MySQL support not enabled during compile time");
#endif
2020-07-04 08:13:21 +00:00
}
CMysqlConnection::~CMysqlConnection()
{
}
CMysqlConnection *CMysqlConnection::Copy()
{
return new CMysqlConnection(m_aDatabase, GetPrefix(), m_aUser, m_aPass, m_aIp, m_Port, m_Setup);
2020-07-04 08:13:21 +00:00
}
IDbConnection::Status CMysqlConnection::Connect()
{
#if defined(CONF_SQL)
2020-07-04 08:13:21 +00:00
if(m_InUse.exchange(true))
return Status::IN_USE;
m_NewQuery = true;
if(m_pConnection != nullptr)
{
try
{
// Connect to specific database
m_pConnection->setSchema(m_aDatabase);
return Status::SUCCESS;
}
catch (sql::SQLException &e)
{
dbg_msg("sql", "MySQL Error: %s", e.what());
}
catch (const std::exception& ex)
{
dbg_msg("sql", "MySQL Error: %s", ex.what());
}
catch (const std::string& ex)
{
dbg_msg("sql", "MySQL Error: %s", ex.c_str());
}
catch (...)
{
dbg_msg("sql", "Unknown Error cause by the MySQL/C++ Connector");
}
m_InUse.store(false);
dbg_msg("sql", "ERROR: SQL connection failed");
return Status::ERROR;
}
try
{
m_pConnection.release();
m_pPreparedStmt.release();
m_pResults.release();
sql::ConnectOptionsMap connection_properties;
connection_properties["hostName"] = sql::SQLString(m_aIp);
connection_properties["port"] = m_Port;
connection_properties["userName"] = sql::SQLString(m_aUser);
connection_properties["password"] = sql::SQLString(m_aPass);
connection_properties["OPT_CONNECT_TIMEOUT"] = 10;
connection_properties["OPT_READ_TIMEOUT"] = 10;
connection_properties["OPT_WRITE_TIMEOUT"] = 20;
connection_properties["OPT_RECONNECT"] = true;
connection_properties["OPT_CHARSET_NAME"] = sql::SQLString("utf8mb4");
connection_properties["OPT_SET_CHARSET_NAME"] = sql::SQLString("utf8mb4");
// Create connection
{
scope_lock GlobalLockScope(&m_SqlDriverLock);
sql::Driver *pDriver = get_driver_instance();
m_pConnection.reset(pDriver->connect(connection_properties));
}
// Create Statement
m_pStmt = std::unique_ptr<sql::Statement>(m_pConnection->createStatement());
// Apparently OPT_CHARSET_NAME and OPT_SET_CHARSET_NAME are not enough
m_pStmt->execute("SET CHARACTER SET utf8mb4;");
if(m_Setup)
{
char aBuf[1024];
// create database
str_format(aBuf, sizeof(aBuf), "CREATE DATABASE IF NOT EXISTS %s CHARACTER SET utf8mb4", m_aDatabase);
m_pStmt->execute(aBuf);
// Connect to specific database
m_pConnection->setSchema(m_aDatabase);
FormatCreateRace(aBuf, sizeof(aBuf));
m_pStmt->execute(aBuf);
FormatCreateTeamrace(aBuf, sizeof(aBuf), "VARBINARY(16)");
m_pStmt->execute(aBuf);
FormatCreateMaps(aBuf, sizeof(aBuf));
m_pStmt->execute(aBuf);
FormatCreateSaves(aBuf, sizeof(aBuf));
m_pStmt->execute(aBuf);
FormatCreatePoints(aBuf, sizeof(aBuf));
m_pStmt->execute(aBuf);
m_Setup = false;
}
else
{
// Connect to specific database
m_pConnection->setSchema(m_aDatabase);
}
dbg_msg("sql", "sql connection established");
return Status::SUCCESS;
}
catch (sql::SQLException &e)
{
dbg_msg("sql", "MySQL Error: %s", e.what());
}
catch (const std::exception& ex)
{
dbg_msg("sql", "MySQL Error: %s", ex.what());
}
catch (const std::string& ex)
{
dbg_msg("sql", "MySQL Error: %s", ex.c_str());
}
catch (...)
{
dbg_msg("sql", "Unknown Error cause by the MySQL/C++ Connector");
}
#endif
dbg_msg("sql", "ERROR: sql connection failed");
2020-07-04 08:13:21 +00:00
return Status::ERROR;
}
void CMysqlConnection::Disconnect()
{
m_InUse.store(false);
}
void CMysqlConnection::Lock(const char *pTable)
2020-07-04 08:13:21 +00:00
{
#if defined(CONF_SQL)
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "lock tables %s write;", pTable);
m_pStmt->execute(aBuf);
m_Locked = true;
#endif
2020-07-04 08:13:21 +00:00
}
void CMysqlConnection::Unlock()
{
#if defined(CONF_SQL)
if(m_Locked)
{
m_pStmt->execute("unlock tables;");
m_Locked = false;
}
#endif
2020-07-04 08:13:21 +00:00
}
void CMysqlConnection::PrepareStatement(const char *pStmt)
{
#if defined(CONF_SQL)
m_pPreparedStmt.reset(m_pConnection->prepareStatement(pStmt));
m_NewQuery = true;
#endif
2020-07-04 08:13:21 +00:00
}
void CMysqlConnection::BindString(int Idx, const char *pString)
{
#if defined(CONF_SQL)
m_pPreparedStmt->setString(Idx, pString);
m_NewQuery = true;
#endif
2020-07-04 08:13:21 +00:00
}
void CMysqlConnection::BindInt(int Idx, int Value)
{
#if defined(CONF_SQL)
m_pPreparedStmt->setInt(Idx, Value);
m_NewQuery = true;
#endif
2020-07-04 08:13:21 +00:00
}
bool CMysqlConnection::Step()
2020-07-04 08:13:21 +00:00
{
#if defined(CONF_SQL)
if(m_NewQuery)
{
m_NewQuery = false;
m_pResults.reset(m_pPreparedStmt->executeQuery());
}
return m_pResults->next();
#else
return false;
#endif
2020-07-04 08:13:21 +00:00
}
bool CMysqlConnection::IsNull(int Col) const
2020-07-04 08:13:21 +00:00
{
#if defined(CONF_SQL)
return m_pResults->isNull(Col);
#else
2020-07-04 08:13:21 +00:00
return false;
#endif
}
float CMysqlConnection::GetFloat(int Col) const
{
#if defined(CONF_SQL)
return (float)m_pResults->getDouble(Col);
#else
return 0.0;
#endif
2020-07-04 08:13:21 +00:00
}
int CMysqlConnection::GetInt(int Col) const
{
#if defined(CONF_SQL)
return m_pResults->getInt(Col);
#else
2020-07-04 08:13:21 +00:00
return 0;
#endif
2020-07-04 08:13:21 +00:00
}
void CMysqlConnection::GetString(int Col, char *pBuffer, int BufferSize) const
{
#if defined(CONF_SQL)
auto String = m_pResults->getString(Col);
str_copy(pBuffer, String.c_str(), BufferSize);
#endif
2020-07-04 08:13:21 +00:00
}
int CMysqlConnection::GetBlob(int Col, unsigned char *pBuffer, int BufferSize) const
{
#if defined(CONF_SQL)
auto Blob = m_pResults->getBlob(Col);
Blob->read((char *)pBuffer, BufferSize);
return Blob->gcount();
#else
2020-07-04 08:13:21 +00:00
return 0;
#endif
2020-07-04 08:13:21 +00:00
}