From ab9ce0151a7098571bfd61e21f45921b083510df Mon Sep 17 00:00:00 2001 From: insunaa Date: Mon, 16 Oct 2023 19:18:35 +0200 Subject: [PATCH] SQLite: SQLite DB backend support --- CMakeLists.txt | 4 + src/game/Accounts/AccountMgr.cpp | 5 +- src/game/Calendar/Calendar.cpp | 5 +- src/game/Chat/Level2.cpp | 6 +- src/game/Chat/Level3.cpp | 2 +- src/game/GameEvents/GameEventMgr.cpp | 2 +- src/game/Maps/MapPersistentStateMgr.cpp | 4 +- src/game/Server/WorldSocket.cpp | 6 +- src/game/World/World.cpp | 20 +- src/realmd/AuthSocket.cpp | 10 +- src/realmd/Main.cpp | 4 +- src/shared/CMakeLists.txt | 7 + src/shared/Database/Database.h | 1 + src/shared/Database/DatabaseEnv.h | 21 ++ src/shared/Database/DatabaseMysql.cpp | 2 + src/shared/Database/DatabaseMysql.h | 2 + src/shared/Database/DatabaseSqlite.cpp | 384 ++++++++++++++++++++++ src/shared/Database/DatabaseSqlite.h | 105 ++++++ src/shared/Database/QueryResultMysql.cpp | 2 + src/shared/Database/QueryResultMysql.h | 2 + src/shared/Database/QueryResultSqlite.cpp | 106 ++++++ src/shared/Database/QueryResultSqlite.h | 55 ++++ src/shared/Database/SqlDelayThread.cpp | 4 + 23 files changed, 728 insertions(+), 31 deletions(-) create mode 100644 src/shared/Database/DatabaseSqlite.cpp create mode 100644 src/shared/Database/DatabaseSqlite.h create mode 100644 src/shared/Database/QueryResultSqlite.cpp create mode 100644 src/shared/Database/QueryResultSqlite.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ecfe45ba29..4494a8e6743 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -251,6 +251,8 @@ endif() if(UNIX AND (BUILD_GAME_SERVER OR BUILD_LOGIN_SERVER OR BUILD_EXTRACTORS)) if(POSTGRESQL) find_package(PostgreSQL REQUIRED) + elseif(SQLITE) + find_package(SQLite3 REQUIRED) else() find_package(MySQL REQUIRED) endif() @@ -359,6 +361,8 @@ set(DEFINITIONS "") if(POSTGRESQL) set(DEFINITIONS ${DEFINITIONS} DO_POSTGRESQL) +elseif(SQLITE) + set(DEFINITIONS ${DEFINITIONS} DO_SQLITE) else() set(DEFINITIONS ${DEFINITIONS} DO_MYSQL) endif() diff --git a/src/game/Accounts/AccountMgr.cpp b/src/game/Accounts/AccountMgr.cpp index 559360b29db..008685db733 100644 --- a/src/game/Accounts/AccountMgr.cpp +++ b/src/game/Accounts/AccountMgr.cpp @@ -56,9 +56,8 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass const char* v_hex = srp.GetVerifier().AsHexStr(); bool update_sv = LoginDatabase.PExecute( - "INSERT INTO account(username,v,s,joindate) VALUES('%s','%s','%s',NOW())", + "INSERT INTO account(username,v,s,joindate) VALUES('%s','%s','%s'," _NOW_ ")", username.c_str(), v_hex, s_hex); - OPENSSL_free((void*)s_hex); OPENSSL_free((void*)v_hex); @@ -90,7 +89,7 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass const char* v_hex = srp.GetVerifier().AsHexStr(); bool update_sv = LoginDatabase.PExecute( - "INSERT INTO account(username,v,s,joindate,expansion) VALUES('%s','%s','%s',NOW(), %u)", + "INSERT INTO account(username,v,s,joindate,expansion) VALUES('%s','%s','%s'," _NOW_ ",%u)", username.c_str(), v_hex, s_hex, expansion); OPENSSL_free((void*)s_hex); diff --git a/src/game/Calendar/Calendar.cpp b/src/game/Calendar/Calendar.cpp index 92c5b27f1ae..d95fede6532 100644 --- a/src/game/Calendar/Calendar.cpp +++ b/src/game/Calendar/Calendar.cpp @@ -18,6 +18,7 @@ #include #include "Calendar/Calendar.h" +#include "Database/DatabaseEnv.h" #include "Mails/Mail.h" #include "Globals/ObjectMgr.h" #include "Util/ProgressBar.h" @@ -625,7 +626,7 @@ void CalendarMgr::LoadCalendarsFromDB() // delete all events (no event exist without at least one invite) m_EventStore.clear(); m_MaxEventId = 0; - CharacterDatabase.DirectExecute("TRUNCATE TABLE calendar_events"); + CharacterDatabase.DirectExecute(_TRUNCATE_ " calendar_events"); sLog.outString(">> calendar_invites table is empty, cleared calendar_events table!"); } else @@ -673,7 +674,7 @@ void CalendarMgr::LoadCalendarsFromDB() else { // delete all invites (no invites exist without events) - CharacterDatabase.DirectExecute("TRUNCATE TABLE calendar_invites"); + CharacterDatabase.DirectExecute(_TRUNCATE_ " calendar_invites"); sLog.outString(">> calendar_invites table is cleared! (invites without events found)"); } } diff --git a/src/game/Chat/Level2.cpp b/src/game/Chat/Level2.cpp index bdfc6e23097..ecc6fd819f1 100644 --- a/src/game/Chat/Level2.cpp +++ b/src/game/Chat/Level2.cpp @@ -853,7 +853,7 @@ bool ChatHandler::HandleGameObjectTargetCommand(char* args) uint32 id; if (ExtractUInt32(&cId, id)) { - queryResult = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE map = '%i' AND guid = '%u' ORDER BY order_ ASC LIMIT 1", + queryResult = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ FROM gameobject WHERE map = '%i' AND guid = '%u' ORDER BY order_ ASC LIMIT 1", pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(), id); } else @@ -1253,8 +1253,8 @@ bool ChatHandler::HandleGameObjectNearCommand(char* args) Player* pl = m_session->GetPlayer(); auto queryResult = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, map, " - "(POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ " - "FROM gameobject WHERE map='%u' AND (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) <= '%f' ORDER BY order_", + "(POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ " + "FROM gameobject WHERE map='%u' AND (POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) <= %f ORDER BY order_", pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(), pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), distance * distance); diff --git a/src/game/Chat/Level3.cpp b/src/game/Chat/Level3.cpp index d53577098a3..d223eaa80f2 100644 --- a/src/game/Chat/Level3.cpp +++ b/src/game/Chat/Level3.cpp @@ -5847,7 +5847,7 @@ bool ChatHandler::HandleBanInfoIPCommand(char* args) bool ChatHandler::HandleBanListCharacterCommand(char* args) { - LoginDatabase.Execute("DELETE FROM ip_banned WHERE expires_at<=UNIX_TIMESTAMP() AND expires_at<>banned_at"); + LoginDatabase.Execute("DELETE FROM ip_banned WHERE expires_at<=" _UNIXTIME_ " AND expires_at<>banned_at"); char* cFilter = ExtractLiteralArg(&args); if (!cFilter) diff --git a/src/game/GameEvents/GameEventMgr.cpp b/src/game/GameEvents/GameEventMgr.cpp index 4b35d85dbd5..ebc2baafc43 100644 --- a/src/game/GameEvents/GameEventMgr.cpp +++ b/src/game/GameEvents/GameEventMgr.cpp @@ -763,7 +763,7 @@ uint32 GameEventMgr::Initialize() // return the next e } while (queryResult->NextRow()); - CharacterDatabase.Execute("TRUNCATE game_event_status"); + CharacterDatabase.Execute(_TRUNCATE_ " game_event_status"); } uint32 delay = Update(&activeAtShutdown); diff --git a/src/game/Maps/MapPersistentStateMgr.cpp b/src/game/Maps/MapPersistentStateMgr.cpp index 376f23f6037..99097667a16 100644 --- a/src/game/Maps/MapPersistentStateMgr.cpp +++ b/src/game/Maps/MapPersistentStateMgr.cpp @@ -1067,7 +1067,7 @@ void MapPersistentStateManager::InitWorldMaps() void MapPersistentStateManager::LoadCreatureRespawnTimes() { // remove outdated data - CharacterDatabase.DirectExecute("DELETE FROM creature_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())"); + CharacterDatabase.DirectExecute("DELETE FROM creature_respawn WHERE respawntime <= " _UNIXNOW_); uint32 count = 0; @@ -1136,7 +1136,7 @@ void MapPersistentStateManager::LoadCreatureRespawnTimes() void MapPersistentStateManager::LoadGameobjectRespawnTimes() { // remove outdated data - CharacterDatabase.DirectExecute("DELETE FROM gameobject_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())"); + CharacterDatabase.DirectExecute("DELETE FROM gameobject_respawn WHERE respawntime <= " _UNIXNOW_); uint32 count = 0; diff --git a/src/game/Server/WorldSocket.cpp b/src/game/Server/WorldSocket.cpp index 8b84553b2a9..df316865b75 100644 --- a/src/game/Server/WorldSocket.cpp +++ b/src/game/Server/WorldSocket.cpp @@ -451,9 +451,9 @@ bool WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // Re-check account ban (same check as in realmd) auto banresult = - LoginDatabase.PQuery("SELECT 1 FROM account_banned WHERE account_id = %u AND active = 1 AND (expires_at > UNIX_TIMESTAMP() OR expires_at = banned_at)" + LoginDatabase.PQuery("SELECT 1 FROM account_banned WHERE account_id = %u AND active = 1 AND (expires_at > " _UNIXTIME_ " OR expires_at = banned_at)" "UNION " - "SELECT 1 FROM ip_banned WHERE (expires_at = banned_at OR expires_at > UNIX_TIMESTAMP()) AND ip = '%s'", + "SELECT 1 FROM ip_banned WHERE (expires_at = banned_at OR expires_at > " _UNIXTIME_ ") AND ip = '%s'", id, GetRemoteAddress().c_str()); if (banresult) // if account banned @@ -525,7 +525,7 @@ bool WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // No SQL injection, username escaped. static SqlStatementID updAccount; - SqlStatement stmt = LoginDatabase.CreateStatement(updAccount, "INSERT INTO account_logons(accountId,ip,loginTime,loginSource) VALUES(?,?,NOW(),?)"); + SqlStatement stmt = LoginDatabase.CreateStatement(updAccount, "INSERT INTO account_logons(accountId,ip,loginTime,loginSource) VALUES(?,?," _NOW_ ",?)"); stmt.PExecute(id, address.c_str(), std::to_string(LOGIN_TYPE_MANGOSD).c_str()); m_crypt.Init(&K); diff --git a/src/game/World/World.cpp b/src/game/World/World.cpp index a8d01c6be10..7e02e59c847 100644 --- a/src/game/World/World.cpp +++ b/src/game/World/World.cpp @@ -952,7 +952,7 @@ void World::SetInitialWorldSettings() LoginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%u'", server_type, realm_zone, realmID); ///- Remove the bones (they should not exist in DB though) and old corpses after a restart - CharacterDatabase.PExecute("DELETE FROM corpse WHERE corpse_type = '0' OR time < (UNIX_TIMESTAMP()-'%u')", 3 * DAY); + CharacterDatabase.PExecute("DELETE FROM corpse WHERE corpse_type = '0' OR time < (" _UNIXTIME_ "-'%u')", 3 * DAY); // load SQL dbcs first, other DBCs need them sObjectMgr.LoadSQLDBCs(); @@ -1474,7 +1474,8 @@ void World::SetInitialWorldSettings() CheckLootTemplates_Reference(ids_set); sLog.outString("Deleting expired bans..."); - LoginDatabase.Execute("DELETE FROM ip_banned WHERE expires_at<=UNIX_TIMESTAMP() AND expires_at<>banned_at"); + + LoginDatabase.Execute("DELETE FROM ip_banned WHERE expires_at<=" _UNIXTIME_ " AND expires_at<>banned_at"); sLog.outString(); sLog.outString("Calculate next daily quest reset time..."); @@ -1994,17 +1995,17 @@ void World::WarnAccount(uint32 accountId, std::string from, std::string reason, reason = std::string(type) + ": " + reason; LoginDatabase.escape_string(reason); - LoginDatabase.PExecute("INSERT INTO account_banned (account_id, banned_at, expires_at, banned_by, reason, active) VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+1, '%s', '%s', '0')", + LoginDatabase.PExecute("INSERT INTO account_banned (account_id, banned_at, expires_at, banned_by, reason, active) VALUES ('%u', " _UNIXTIME_ ", " _UNIXTIME_ "+1, '%s', '%s', '0')", accountId, from.c_str(), reason.c_str()); } BanReturn World::BanAccount(WorldSession *session, uint32 duration_secs, const std::string& reason, const std::string& author) { if (duration_secs) - LoginDatabase.PExecute("INSERT INTO account_banned(account_id, banned_at, expires_at, banned_by, reason, active) VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')", + LoginDatabase.PExecute("INSERT INTO account_banned(account_id, banned_at, expires_at, banned_by, reason, active) VALUES ('%u', " _UNIXTIME_ ", " _UNIXTIME_ "+%u, '%s', '%s', '1')", session->GetAccountId(), duration_secs, author.c_str(), reason.c_str()); else - LoginDatabase.PExecute("INSERT INTO account_banned(account_id, banned_at, expires_at, banned_by, reason, active) VALUES ('%u', UNIX_TIMESTAMP(), 0, '%s', '%s', '1')", + LoginDatabase.PExecute("INSERT INTO account_banned(account_id, banned_at, expires_at, banned_by, reason, active) VALUES ('%u', " _UNIXTIME_ ", 0, '%s', '%s', '1')", session->GetAccountId(), author.c_str(), reason.c_str()); session->KickPlayer(); @@ -2027,7 +2028,7 @@ BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, uint32 duration_ case BAN_IP: // No SQL injection as strings are escaped resultAccounts = LoginDatabase.PQuery("SELECT accountId FROM account_logons WHERE ip = '%s' ORDER BY loginTime DESC LIMIT 1", nameOrIP.c_str()); - LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+%u,'%s','%s')", nameOrIP.c_str(), duration_secs, safe_author.c_str(), reason.c_str()); + LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s'," _UNIXTIME_ "," _UNIXTIME_ "+%u,'%s','%s')", nameOrIP.c_str(), duration_secs, safe_author.c_str(), reason.c_str()); break; case BAN_ACCOUNT: // No SQL injection as string is escaped @@ -2058,7 +2059,7 @@ BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, uint32 duration_ if (mode != BAN_IP) { // No SQL injection as strings are escaped - LoginDatabase.PExecute("INSERT INTO account_banned(account_id, banned_at, expires_at, banned_by, reason, active) VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')", + LoginDatabase.PExecute("INSERT INTO account_banned(account_id, banned_at, expires_at, banned_by, reason, active) VALUES ('%u', " _UNIXTIME_ ", " _UNIXTIME_ "+%u, '%s', '%s', '1')", account, duration_secs, safe_author.c_str(), reason.c_str()); } @@ -2091,7 +2092,7 @@ bool World::RemoveBanAccount(BanMode mode, const std::string& source, const std: return false; // NO SQL injection as account is uint32 - LoginDatabase.PExecute("UPDATE account_banned SET active = '0', unbanned_at = UNIX_TIMESTAMP(), unbanned_by = '%s' WHERE account_id = '%u'", source.data(), account); + LoginDatabase.PExecute("UPDATE account_banned SET active = '0', unbanned_at = " _UNIXTIME_ ", unbanned_by = '%s' WHERE account_id = '%u'", source.data(), account); WarnAccount(account, source, message, "UNBAN"); } return true; @@ -2541,7 +2542,8 @@ void World::ResetWeeklyQuests() void World::ResetMonthlyQuests() { DETAIL_LOG("Monthly quests reset for all characters."); - CharacterDatabase.Execute("TRUNCATE character_queststatus_monthly"); + + CharacterDatabase.Execute(_TRUNCATE_ " character_queststatus_monthly"); for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) if (itr->second->GetPlayer()) diff --git a/src/realmd/AuthSocket.cpp b/src/realmd/AuthSocket.cpp index 1821e054de4..2789b91a4c1 100644 --- a/src/realmd/AuthSocket.cpp +++ b/src/realmd/AuthSocket.cpp @@ -382,7 +382,7 @@ bool AuthSocket::_HandleLogonChallenge() ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) std::unique_ptr ip_banned_result(LoginDatabase.PQuery("SELECT expires_at FROM ip_banned " - "WHERE (expires_at = banned_at OR expires_at > UNIX_TIMESTAMP()) AND ip = '%s'", m_address.c_str())); + "WHERE (expires_at = banned_at OR expires_at > " _UNIXTIME_ ") AND ip = '%s'", m_address.c_str())); if (ip_banned_result) { @@ -431,7 +431,7 @@ bool AuthSocket::_HandleLogonChallenge() { ///- If the account is banned, reject the logon attempt auto banresult = LoginDatabase.PQuery("SELECT banned_at,expires_at FROM account_banned WHERE " - "account_id = %u AND active = 1 AND (expires_at > UNIX_TIMESTAMP() OR expires_at = banned_at)", fields[0].GetUInt32()); + "account_id = %u AND active = 1 AND (expires_at > " _UNIXTIME_ " OR expires_at = banned_at)", fields[0].GetUInt32()); if (banresult) { if ((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) @@ -595,7 +595,7 @@ bool AuthSocket::_HandleLogonProof() LoginDatabase.PExecute("UPDATE account SET sessionkey = '%s', locale = '%s', failed_logins = 0, os = '%s', platform = '%s' WHERE username = '%s'", K_hex, _safelocale.c_str(), m_os.c_str(), m_platform.c_str(), _safelogin.c_str()); std::unique_ptr loginfail(LoginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'", _safelogin.c_str())); if (loginfail) - LoginDatabase.PExecute("INSERT INTO account_logons(accountId,ip,loginTime,loginSource) VALUES('%u','%s',NOW(),'%u')", loginfail->Fetch()[0].GetUInt32(), m_address.c_str(), LOGIN_TYPE_REALMD); + LoginDatabase.PExecute("INSERT INTO account_logons(accountId,ip,loginTime,loginSource) VALUES('%u','%s'," _NOW_ ",'%u')", loginfail->Fetch()[0].GetUInt32(), m_address.c_str(), LOGIN_TYPE_REALMD); OPENSSL_free((void*)K_hex); ///- Finish SRP6 and send the final result to the client @@ -643,7 +643,7 @@ bool AuthSocket::_HandleLogonProof() { uint32 acc_id = fields[0].GetUInt32(); LoginDatabase.PExecute("INSERT INTO account_banned(account_id, banned_at, expires_at, banned_by, reason, active)" - "VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban',1)", + "VALUES ('%u'," _UNIXTIME_ "," _UNIXTIME_ "+'%u','MaNGOS realmd','Failed login autoban',1)", acc_id, WrongPassBanTime); BASIC_LOG("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", _login.c_str(), WrongPassBanTime, failed_logins); @@ -652,7 +652,7 @@ bool AuthSocket::_HandleLogonProof() { std::string current_ip = m_address; LoginDatabase.escape_string(current_ip); - LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban')", + LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s'," _UNIXTIME_ "," _UNIXTIME_ "+'%u','MaNGOS realmd','Failed login autoban')", current_ip.c_str(), WrongPassBanTime); BASIC_LOG("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", current_ip.c_str(), WrongPassBanTime, _login.c_str(), failed_logins); diff --git a/src/realmd/Main.cpp b/src/realmd/Main.cpp index 70895d5d520..686ead102a6 100644 --- a/src/realmd/Main.cpp +++ b/src/realmd/Main.cpp @@ -227,8 +227,8 @@ int main(int argc, char* argv[]) // cleanup query // set expired bans to inactive LoginDatabase.BeginTransaction(); - LoginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE expires_at<=UNIX_TIMESTAMP() AND expires_at<>banned_at"); - LoginDatabase.Execute("DELETE FROM ip_banned WHERE expires_at<=UNIX_TIMESTAMP() AND expires_at<>banned_at"); + LoginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE expires_at<=" _UNIXTIME_ " AND expires_at<>banned_at"); + LoginDatabase.Execute("DELETE FROM ip_banned WHERE expires_at<=" _UNIXTIME_ " AND expires_at<>banned_at"); LoginDatabase.CommitTransaction(); // FIXME - more intelligent selection of thread count is needed here. config option? diff --git a/src/shared/CMakeLists.txt b/src/shared/CMakeLists.txt index 89dd9dd54b1..fa84c8ef9d1 100644 --- a/src/shared/CMakeLists.txt +++ b/src/shared/CMakeLists.txt @@ -46,6 +46,8 @@ set(SRC_GRP_DATABASE Database/DatabaseMysql.h Database/DatabasePostgre.cpp Database/DatabasePostgre.h + Database/DatabaseSqlite.cpp + Database/DatabaseSqlite.h Database/Field.cpp Database/Field.h Database/PGSQLDelayThread.h @@ -54,6 +56,8 @@ set(SRC_GRP_DATABASE Database/QueryResultMysql.h Database/QueryResultPostgre.cpp Database/QueryResultPostgre.h + Database/QueryResultSqlite.cpp + Database/QueryResultSqlite.h Database/SqlDelayThread.cpp Database/SqlDelayThread.h Database/SqlOperations.cpp @@ -244,6 +248,9 @@ endif() if(POSTGRESQL AND POSTGRESQL_FOUND) target_include_directories(${LIBRARY_NAME} PUBLIC ${PostgreSQL_INCLUDE_DIRS}) target_link_libraries(${LIBRARY_NAME} PUBLIC ${PostgreSQL_LIBRARIES}) +elseif(SQLITE AND SQLite3_FOUND) + target_include_directories(${LIBRARY_NAME} PUBLIC ${SQLite3_INCLUDE_DIRS}) + target_link_libraries(${LIBRARY_NAME} PUBLIC ${SQLite3_LIBRARIES}) else() target_include_directories(${LIBRARY_NAME} PUBLIC ${MYSQL_INCLUDE_DIR}) target_link_libraries(${LIBRARY_NAME} PUBLIC ${MYSQL_LIBRARY}) diff --git a/src/shared/Database/Database.h b/src/shared/Database/Database.h index 80941aaeac6..e11773b8fa3 100644 --- a/src/shared/Database/Database.h +++ b/src/shared/Database/Database.h @@ -24,6 +24,7 @@ #include "Database/SqlDelayThread.h" #include "Policies/ThreadingModel.h" #include "SqlPreparedStatement.h" +#include "QueryResult.h" #include #include diff --git a/src/shared/Database/DatabaseEnv.h b/src/shared/Database/DatabaseEnv.h index ea7b4658ef1..a21b4d03564 100644 --- a/src/shared/Database/DatabaseEnv.h +++ b/src/shared/Database/DatabaseEnv.h @@ -35,6 +35,23 @@ typedef DatabasePostgre DatabaseType; #define _TABLE_SIM_ "\"" #define _CONCAT3_(A,B,C) "( " A " || " B " || " C " )" #define _OFFSET_ "LIMIT 1 OFFSET %d" +#define _TRUNCATE_ "TRUNCATE TABLE" +#define _NOW_ "NOW()" +#define _UNIXTIME_ "UNIX_TIMESTAMP()" +#define _UNIXNOW_ "UNIX_TIMESTAMP(NOW())" +#elif DO_SQLITE +#include "Database/QueryResultSqlite.h" +#include "Database/Database.h" +#include "Database/DatabaseSqlite.h" +typedef DatabaseSqlite DatabaseType; +#define _LIKE_ "LIKE" +#define _TABLE_SIM_ '`' +#define _CONCAT3_(A,B,C) "( " A " || " B " || " C " )" +#define _OFFSET_ "LIMIT %d,1" +#define _TRUNCATE_ "DELETE FROM" +#define _NOW_ "datetime()" +#define _UNIXTIME_ "unixepoch()" +#define _UNIXNOW_ "unixepoch('now')" #else #include "Database/QueryResultMysql.h" #include "Database/Database.h" @@ -44,6 +61,10 @@ typedef DatabaseMysql DatabaseType; #define _TABLE_SIM_ '`' #define _CONCAT3_(A,B,C) "CONCAT( " A " , " B " , " C " )" #define _OFFSET_ "LIMIT %d,1" +#define _TRUNCATE_ "TRUNCATE TABLE" +#define _NOW_ "NOW()" +#define _UNIXTIME_ "UNIX_TIMESTAMP()" +#define _UNIXNOW_ "UNIX_TIMESTAMP(NOW())" #endif extern DatabaseType WorldDatabase; diff --git a/src/shared/Database/DatabaseMysql.cpp b/src/shared/Database/DatabaseMysql.cpp index c10d03ce672..4bd4b2069c9 100644 --- a/src/shared/Database/DatabaseMysql.cpp +++ b/src/shared/Database/DatabaseMysql.cpp @@ -17,6 +17,7 @@ */ #ifndef DO_POSTGRESQL +#ifndef DO_SQLITE #include "Util/Util.h" #include "Policies/Singleton.h" @@ -487,3 +488,4 @@ enum_field_types MySqlPreparedStatement::ToMySQLType(const SqlStmtFieldData& dat return dataType; } #endif +#endif diff --git a/src/shared/Database/DatabaseMysql.h b/src/shared/Database/DatabaseMysql.h index c3db0c1d983..bdf0dcb05be 100644 --- a/src/shared/Database/DatabaseMysql.h +++ b/src/shared/Database/DatabaseMysql.h @@ -17,6 +17,7 @@ */ #ifndef DO_POSTGRESQL +#ifndef DO_SQLITE #ifndef _DATABASEMYSQL_H #define _DATABASEMYSQL_H @@ -111,3 +112,4 @@ class DatabaseMysql : public Database #endif #endif +#endif diff --git a/src/shared/Database/DatabaseSqlite.cpp b/src/shared/Database/DatabaseSqlite.cpp new file mode 100644 index 00000000000..a0e05a2edee --- /dev/null +++ b/src/shared/Database/DatabaseSqlite.cpp @@ -0,0 +1,384 @@ +/* + * This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "QueryResultSqlite.h" +#include +#include +#include +#ifdef DO_SQLITE + +#include "Util/Util.h" +#include "Policies/Singleton.h" +#include "Platform/Define.h" +#include "Multithreading/Threading.h" +#include "DatabaseEnv.h" +#include "Util/Timer.h" +#include "DatabaseSqlite.h" + +size_t DatabaseSqlite::db_count = 0; + +DatabaseSqlite::DatabaseSqlite() +{ + // before first connection + if (db_count++ == 0); +} + +DatabaseSqlite::~DatabaseSqlite() +{ + StopServer(); + if (--db_count == 0); +} + +SqlConnection* DatabaseSqlite::CreateConnection() +{ + return new SQLiteConnection(*this); +} + +SQLiteConnection::~SQLiteConnection() +{ + FreePreparedStatements(); + sqlite3_exec(mSqlite, "PRAGMA optimize;", 0, 0, 0); + sqlite3_close(mSqlite); +} + +bool SQLiteConnection::Initialize(const char* infoString) +{ + if (sqlite3_open(infoString, &mSqlite) != SQLITE_OK) + { + sLog.outError("Could not open SQLite database"); + return false; + } + sqlite3_exec(mSqlite, "PRAGMA journal_mode=WAL;", 0, 0, 0); + sqlite3_exec(mSqlite, "PRAGMA synchronous=1;", 0, 0, 0); + sqlite3_exec(mSqlite, "PRAGMA secure_delete=off;", 0, 0, 0); + sqlite3_exec(mSqlite, "PRAGMA encoding='UTF-8';", 0, 0, 0); + sqlite3_busy_timeout(mSqlite, 2); + + Tokens tokens = StrSplit(infoString, ";"); + + DETAIL_LOG("Connected to SQLite database at %s", infoString); + + return true; +} + +bool SQLiteConnection::_Query(const char* sql, sqlite3_stmt** pStmt) +{ + if (!mSqlite) + return false; + + uint32 _s = WorldTimer::getMSTime(); + int result; + result = sqlite3_prepare_v2(mSqlite, sql, -1, pStmt, NULL); + if (result != SQLITE_OK) { + sLog.outErrorDb("SQL: %s", sql); + sLog.outErrorDb("query ERROR: %s", sqlite3_errmsg(mSqlite)); + return false; + } + + return true; +} + +std::unique_ptr SQLiteConnection::Query(const char* sql) +{ + sqlite3_stmt** pStmt = new(sqlite3_stmt*); + if (!_Query(sql, pStmt)) + return nullptr; + + auto queryResult = std::make_unique(pStmt); + + if (queryResult->NextRow()) + return queryResult; + return nullptr; +} + +QueryNamedResult* SQLiteConnection::QueryNamed(const char* sql) +{ + uint64 rowCount = 0; + uint32 fieldCount = 0; + + sqlite3_stmt** pStmt = new(sqlite3_stmt*); + + if (!_Query(sql, pStmt)) + return nullptr; + + fieldCount = sqlite3_column_count(*pStmt); + + QueryFieldNames names(fieldCount); + for (uint32 i = 0; i < fieldCount; ++i) + names[i] = sqlite3_column_name(*pStmt, i); + + QueryResultSqlite* queryResult = new QueryResultSqlite(pStmt); + + queryResult->NextRow(); + return new QueryNamedResult(queryResult, names); +} + +bool SQLiteConnection::Execute(const char* sql) +{ + if (!mSqlite) + return false; + + { + uint32 _s = WorldTimer::getMSTime(); + sqlite3_stmt** pStmt = new(sqlite3_stmt*); + + int result; + result = sqlite3_prepare_v2(mSqlite, sql, -1, pStmt, NULL); + if (result != SQLITE_OK) + { + sLog.outErrorDb("SQL: %s", sql); + sLog.outErrorDb("SQL ERROR: %s", sqlite3_errmsg(mSqlite)); + return false; + } + result = sqlite3_step(*pStmt); + if (result != SQLITE_DONE && result != SQLITE_OK) + { + sLog.outErrorDb("SQL: %s", sql); + sLog.outErrorDb("SQL ERROR: %s", sqlite3_errmsg(mSqlite)); + return false; + } + sqlite3_finalize(*pStmt); + DEBUG_FILTER_LOG(LOG_FILTER_SQL_TEXT, "[%u ms] SQL: %s", WorldTimer::getMSTimeDiff(_s, WorldTimer::getMSTime()), sql); + // end guarded block + } + + return true; +} + +bool SQLiteConnection::_TransactionCmd(const char* sql) +{ + sqlite3_stmt** pStmt = new(sqlite3_stmt*); + + int result; + result = sqlite3_prepare_v2(mSqlite, sql, -1, pStmt, NULL); + if (result != SQLITE_OK) + { + sLog.outErrorDb("SQL: %s", sql); + sLog.outErrorDb("SQL ERROR: %s", sqlite3_errmsg(mSqlite)); + return false; + } + result = sqlite3_step(*pStmt); + if (result != SQLITE_DONE && result != SQLITE_OK) + { + sLog.outErrorDb("SQL: %s", sql); + sLog.outErrorDb("SQL ERROR: %s", sqlite3_errmsg(mSqlite)); + return false; + } + DEBUG_FILTER_LOG(LOG_FILTER_SQL_TEXT, "SQL: %s", sql); + return true; +} + +bool SQLiteConnection::BeginTransaction() +{ + return _TransactionCmd("BEGIN"); +} + +bool SQLiteConnection::CommitTransaction() +{ + return _TransactionCmd("COMMIT"); +} + +bool SQLiteConnection::RollbackTransaction() +{ + return _TransactionCmd("ROLLBACK"); +} + +unsigned long SQLiteConnection::escape_string(char* to, const char* from, unsigned long length) +{ + if (!mSqlite || !to || !from || !length) + return 0; + std::string newFrom(from); + std::string newTo; + + for (const char& c : newFrom) + { + switch (c) + { + [[unlikely]] case '\'': newTo += "''"; break; + [[unlikely]] case '\\': newTo += "\\"; break; + [[likely]] default: newTo += c; break; + } + } + strcpy(to, newTo.c_str()); + + return newTo.length(); +} + +////////////////////////////////////////////////////////////////////////// +SqlPreparedStatement* SQLiteConnection::CreateStatement(const std::string& fmt) +{ + return new SqlitePreparedStatement(fmt, *this, mSqlite); +} + +////////////////////////////////////////////////////////////////////////// +SqlitePreparedStatement::SqlitePreparedStatement(const std::string& fmt, SqlConnection& conn, sqlite3* mysql) : SqlPreparedStatement(fmt, conn), + m_pSqliteConn(mysql), m_stmt(nullptr), m_pResult(nullptr) +{ +} + +SqlitePreparedStatement::~SqlitePreparedStatement() +{ + RemoveBinds(); +} + +bool SqlitePreparedStatement::prepare() +{ + if (isPrepared()) + return true; + + // remove old binds + RemoveBinds(); + + if (!m_stmt) + m_stmt = new(sqlite3_stmt*); + + // Create statement object + int result = sqlite3_prepare_v2(m_pSqliteConn, m_szFmt.c_str(), m_szFmt.length(), m_stmt, nullptr); + if (result != SQLITE_OK) { + sLog.outError("SQL: sqlite3_prepare_v2() failed: %s", sqlite3_errmsg(m_pSqliteConn)); + return false; + } + // Get the parameter count from the statement + m_nParams = sqlite3_bind_parameter_count(*m_stmt); + + // Check if we have a statement which returns result sets + if (sqlite3_stmt_readonly(*m_stmt) == 0) { + // Our statement is a query + m_bIsQuery = true; + m_nColumns = sqlite3_column_count(*m_stmt); // Get the number of columns in the result set + } + + m_bPrepared = true; + return true; +} + +void SqlitePreparedStatement::bind(const SqlStmtParameters& holder) +{ + if (!isPrepared()) + { + MANGOS_ASSERT(!isPrepared()); + return; + } + + // verify if we bound all needed input parameters + if (m_nParams != holder.boundParams()) + { + MANGOS_ASSERT(m_nParams != holder.boundParams()); + return; + } + + unsigned int nIndex = 0; // SQLite uses 1-based index for parameter binding + SqlStmtParameters::ParameterContainer const& _args = holder.params(); + + for (const auto& param : _args) + { + // Bind parameter + addParam(nIndex, param); + nIndex++; + } +} + +void SqlitePreparedStatement::addParam(unsigned int nIndex, const SqlStmtFieldData& data) +{ + MANGOS_ASSERT(nIndex < m_nParams); + + // SQLite uses different types and structures for binding parameters + int result = SQLITE_OK; + + switch (data.type()) { + case FIELD_BOOL: + case FIELD_UI8: + result = sqlite3_bind_int(*m_stmt, nIndex + 1, *static_cast(data.buff())); + break; + case FIELD_UI16: + result = sqlite3_bind_int(*m_stmt, nIndex + 1, *static_cast(data.buff())); + break; + case FIELD_UI32: + result = sqlite3_bind_int(*m_stmt, nIndex + 1, *static_cast(data.buff())); + break; + case FIELD_UI64: + result = sqlite3_bind_int64(*m_stmt, nIndex + 1, *static_cast(data.buff())); + break; + case FIELD_I8: + result = sqlite3_bind_int(*m_stmt, nIndex + 1, *static_cast(data.buff())); + break; + case FIELD_I16: + result = sqlite3_bind_int(*m_stmt, nIndex + 1, *static_cast(data.buff())); + break; + case FIELD_I32: + result = sqlite3_bind_int(*m_stmt, nIndex + 1, *static_cast(data.buff())); + break; + case FIELD_I64: + result = sqlite3_bind_int64(*m_stmt, nIndex + 1, *static_cast(data.buff())); + break; + case FIELD_FLOAT: + result = sqlite3_bind_double(*m_stmt, nIndex + 1, *static_cast(data.buff())); + break; + case FIELD_DOUBLE: + result = sqlite3_bind_double(*m_stmt, nIndex + 1, *static_cast(data.buff())); + break; + case FIELD_STRING: + result = sqlite3_bind_text(*m_stmt, nIndex + 1, static_cast(data.buff()), -1, SQLITE_STATIC); + break; + case FIELD_NONE: + result = sqlite3_bind_null(*m_stmt, nIndex + 1); + break; + // Handle other data types as needed + + default: + MANGOS_ASSERT(false && "Unsupported parameter type"); + } + + if (result != SQLITE_OK) { + // Handle the error, e.g., print an error message + fprintf(stderr, "Error binding parameter at index %d: %s\n", nIndex, sqlite3_errmsg(m_pSqliteConn)); + } +} + +void SqlitePreparedStatement::RemoveBinds() +{ + if (!m_stmt) + return; + + // Finalize the prepared statement + sqlite3_finalize(*m_stmt); + *m_stmt = nullptr; + + m_bPrepared = false; +} + +bool SqlitePreparedStatement::execute() +{ + if (!isPrepared()) + return false; + + int result = sqlite3_step(*m_stmt); + + if (result != SQLITE_DONE) + { + sLog.outErrorDb("SQL: cannot execute '%s'", m_szFmt.c_str()); + sLog.outErrorDb("SQL ERROR: %s", sqlite3_errmsg(m_pSqliteConn)); + return false; + } + + // Reset the prepared statement to be executed again if needed + sqlite3_reset(*m_stmt); + + return true; +} +#endif diff --git a/src/shared/Database/DatabaseSqlite.h b/src/shared/Database/DatabaseSqlite.h new file mode 100644 index 00000000000..e2c1eb548ad --- /dev/null +++ b/src/shared/Database/DatabaseSqlite.h @@ -0,0 +1,105 @@ +/* + * This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DO_POSTGRESQL + +#ifndef _DatabaseSqlite_H +#define _DatabaseSqlite_H + +//#include "Common.h" +#include "Database.h" +#include "Policies/Singleton.h" +#include "QueryResultSqlite.h" + +#include + +// MySQL prepared statement class +class SqlitePreparedStatement : public SqlPreparedStatement +{ + public: + SqlitePreparedStatement(const std::string& fmt, SqlConnection& conn, sqlite3* mysql); + ~SqlitePreparedStatement(); + + // prepare statement + virtual bool prepare() override; + + // bind input parameters + virtual void bind(const SqlStmtParameters& holder) override; + + // execute DML statement + virtual bool execute() override; + + protected: + // bind parameters + void addParam(unsigned int nIndex, const SqlStmtFieldData& data); + + private: + void RemoveBinds(); + + sqlite3* m_pSqliteConn; + sqlite3_stmt** m_stmt; + sqlite3_value* m_pResult; +}; + +class SQLiteConnection : public SqlConnection +{ + public: + SQLiteConnection(Database& db) : SqlConnection(db), mSqlite(nullptr) {} + ~SQLiteConnection(); + + //! Initializes Mysql and connects to a server. + /*! infoString should be formated like hostname;username;password;database. */ + bool Initialize(const char* infoString) override; + + std::unique_ptr Query(const char* sql) override; + QueryNamedResult* QueryNamed(const char* sql) override; + bool Execute(const char* sql) override; + + unsigned long escape_string(char* to, const char* from, unsigned long length); + + bool BeginTransaction() override; + bool CommitTransaction() override; + bool RollbackTransaction() override; + + protected: + SqlPreparedStatement* CreateStatement(const std::string& fmt) override; + + private: + bool _TransactionCmd(const char* sql); + bool _Query(const char* sql, sqlite3_stmt** pStmt); + + sqlite3* mSqlite; +}; + +class DatabaseSqlite : public Database +{ + friend class MaNGOS::OperatorNew; + + public: + DatabaseSqlite(); + ~DatabaseSqlite(); + + protected: + virtual SqlConnection* CreateConnection() override; + + private: + static size_t db_count; +}; + +#endif +#endif diff --git a/src/shared/Database/QueryResultMysql.cpp b/src/shared/Database/QueryResultMysql.cpp index f9fec84815a..1c3f1ee9e7b 100644 --- a/src/shared/Database/QueryResultMysql.cpp +++ b/src/shared/Database/QueryResultMysql.cpp @@ -17,6 +17,7 @@ */ #ifndef DO_POSTGRESQL +#ifndef DO_SQLITE #include "DatabaseEnv.h" #include "Util/Errors.h" @@ -97,3 +98,4 @@ enum Field::DataTypes QueryResultMysql::ConvertNativeType(enum_field_types mysql } } #endif +#endif diff --git a/src/shared/Database/QueryResultMysql.h b/src/shared/Database/QueryResultMysql.h index e60745998fb..ddf1fe22af2 100644 --- a/src/shared/Database/QueryResultMysql.h +++ b/src/shared/Database/QueryResultMysql.h @@ -17,6 +17,7 @@ */ #ifndef DO_POSTGRESQL +#ifndef DO_SQLITE #if !defined(QUERYRESULTMYSQL_H) #define QUERYRESULTMYSQL_H @@ -46,3 +47,4 @@ class QueryResultMysql : public QueryResult }; #endif #endif +#endif diff --git a/src/shared/Database/QueryResultSqlite.cpp b/src/shared/Database/QueryResultSqlite.cpp new file mode 100644 index 00000000000..89f682aba06 --- /dev/null +++ b/src/shared/Database/QueryResultSqlite.cpp @@ -0,0 +1,106 @@ +/* + * This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef DO_SQLITE + +#include "DatabaseEnv.h" +#include "Util/Errors.h" +#include "sqlite3.h" +#include "QueryResultSqlite.h" + +QueryResultSqlite::QueryResultSqlite(sqlite3_stmt** stmt) : + QueryResult(0, 0), mStmt(stmt) +{ + if (mStmt && *mStmt) + { + while (sqlite3_step(*mStmt) == SQLITE_ROW) + { + // Process each row's data here + mRowCount++; + } + sqlite3_reset(*mStmt); + mFieldCount = sqlite3_column_count(*mStmt); + mCurrentRow = new Field[mFieldCount]; + MANGOS_ASSERT(mCurrentRow); + + for (int i = 0; i < mFieldCount; ++i) + { + const unsigned char* value = sqlite3_column_text(*mStmt, i); + mCurrentRow[i].SetValue(value ? reinterpret_cast(value) : ""); + mCurrentRow[i].SetType(ConvertNativeType(sqlite3_column_type(*mStmt, i))); + } + } +} + +QueryResultSqlite::~QueryResultSqlite() +{ + EndQuery(); +} + +bool QueryResultSqlite::NextRow() +{ + if (!mStmt || !(*mStmt)) + return false; + + int rc = sqlite3_step(*mStmt); + if (rc != SQLITE_ROW) + { + EndQuery(); + return false; + } + + for (int i = 0; i < mFieldCount; ++i) + { + const unsigned char* value = sqlite3_column_text(*mStmt, i); + mCurrentRow[i].SetValue(value ? reinterpret_cast(value) : ""); + mCurrentRow[i].SetType(ConvertNativeType(sqlite3_column_type(*mStmt, i))); + } + + return true; +} + +void QueryResultSqlite::EndQuery() +{ + if (mStmt && *mStmt) + { + sqlite3_finalize(*mStmt); + *mStmt = nullptr; + //mStmt = nullptr; + } + + delete[] mCurrentRow; + mCurrentRow = nullptr; +} + +enum Field::DataTypes QueryResultSqlite::ConvertNativeType(int sqliteType) const +{ + switch (sqliteType) + { + case SQLITE_INTEGER: + return Field::DB_TYPE_INTEGER; + case SQLITE_FLOAT: + return Field::DB_TYPE_FLOAT; + case SQLITE_TEXT: + case SQLITE_BLOB: + case SQLITE_NULL: + return Field::DB_TYPE_STRING; + default: + return Field::DB_TYPE_UNKNOWN; + } +} +#endif diff --git a/src/shared/Database/QueryResultSqlite.h b/src/shared/Database/QueryResultSqlite.h new file mode 100644 index 00000000000..a9e84ef800b --- /dev/null +++ b/src/shared/Database/QueryResultSqlite.h @@ -0,0 +1,55 @@ +/* + * This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef DO_SQLITE + +#if !defined(QUERYRESULTSQLITE_H) +#define QUERYRESULTSQLITE_H + +#include "Common.h" +#include "QueryResult.h" + +#ifdef _WIN32 + #include +#endif + +#include + +class QueryResultSqlite : public QueryResult +{ + public: + QueryResultSqlite(sqlite3_stmt** stmt); + + ~QueryResultSqlite(); + + bool NextRow() override; + + operator bool() const + { + return (mRowCount * mFieldCount) > 0; + } + + private: + enum Field::DataTypes ConvertNativeType(int sqliteType) const; + //enum Field::DataTypes ConvertNativeType(enum_field_types mysqlType) const; + void EndQuery(); + + sqlite3_stmt** mStmt; +}; +#endif +#endif diff --git a/src/shared/Database/SqlDelayThread.cpp b/src/shared/Database/SqlDelayThread.cpp index 9e86d463e8a..bf4a0495fb7 100644 --- a/src/shared/Database/SqlDelayThread.cpp +++ b/src/shared/Database/SqlDelayThread.cpp @@ -33,7 +33,9 @@ SqlDelayThread::~SqlDelayThread() void SqlDelayThread::run() { #ifndef DO_POSTGRESQL +#ifndef DO_SQLITE mysql_thread_init(); +#endif #endif const uint32 loopSleepms = 10; @@ -57,8 +59,10 @@ void SqlDelayThread::run() } #ifndef DO_POSTGRESQL +#ifndef DO_SQLITE mysql_thread_end(); #endif +#endif } void SqlDelayThread::Stop()