From 8b313ff5e0a70527e4bd545be2b40f9c1a444bb9 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Sat, 4 Jan 2025 01:05:07 -0300 Subject: [PATCH 1/3] perf: replace SELECT * with specific columns in SQL queries Replaced `SELECT *` in SQL queries with explicit column names. This improves query performance by reducing unnecessary data retrieval and ensures better clarity and maintainability in the codebase. --- src/account/account_repository_db.cpp | 2 +- .../players/cyclopedia/player_title.cpp | 4 +- src/game/game.cpp | 62 ++++++++++++------ src/io/functions/iologindata_load_player.cpp | 14 +++-- src/io/io_bosstiary.cpp | 63 +++++++++++-------- 5 files changed, 94 insertions(+), 51 deletions(-) diff --git a/src/account/account_repository_db.cpp b/src/account/account_repository_db.cpp index b2e8fd80754..b46d1941779 100644 --- a/src/account/account_repository_db.cpp +++ b/src/account/account_repository_db.cpp @@ -76,7 +76,7 @@ bool AccountRepositoryDB::getCharacterByAccountIdAndName(const uint32_t &id, con } bool AccountRepositoryDB::getPassword(const uint32_t &id, std::string &password) { - auto result = g_database().storeQuery(fmt::format("SELECT * FROM `accounts` WHERE `id` = {}", id)); + auto result = g_database().storeQuery(fmt::format("SELECT `password` FROM `accounts` WHERE `id` = {}", id)); if (!result) { g_logger().error("Failed to get account:[{}] password!", id); return false; diff --git a/src/creatures/players/cyclopedia/player_title.cpp b/src/creatures/players/cyclopedia/player_title.cpp index 089d02f281c..c7e1c8f04f6 100644 --- a/src/creatures/players/cyclopedia/player_title.cpp +++ b/src/creatures/players/cyclopedia/player_title.cpp @@ -224,7 +224,9 @@ bool PlayerTitle::checkHighscore(uint8_t skill) const { default: std::string skillName = g_game().getSkillNameById(skill); query = fmt::format( - "SELECT * FROM `players` WHERE `group_id` < {} AND `{}` > 10 ORDER BY `{}` DESC LIMIT 1", + "SELECT `id` FROM `players` " + "WHERE `group_id` < {} AND `{}` > 10 " + "ORDER BY `{}` DESC LIMIT 1", static_cast(GROUP_TYPE_GAMEMASTER), skillName, skillName ); break; diff --git a/src/game/game.cpp b/src/game/game.cpp index 7da1d87fb4a..6638cad7cf2 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -440,7 +440,10 @@ void Game::resetNpcs() const { void Game::loadBoostedCreature() { auto &db = Database::getInstance(); - const auto result = db.storeQuery("SELECT * FROM `boosted_creature`"); + const auto result = db.storeQuery( + "SELECT `date`, `boostname`, `raceid`, `looktype`, `lookfeet`, `looklegs`, `lookhead`, `lookbody`, `lookaddons`, `lookmount` " + "FROM `boosted_creature`" + ); if (!result) { g_logger().warn("[Game::loadBoostedCreature] - " "Failed to detect boosted creature database. (CODE 01)"); @@ -8505,38 +8508,61 @@ void Game::playerCyclopediaCharacterInfo(const std::shared_ptr &player, } std::string Game::generateHighscoreQueryForEntries(const std::string &categoryName, uint32_t page, uint8_t entriesPerPage, uint32_t vocation) { - std::ostringstream query; - uint32_t startPage = (static_cast(page - 1) * static_cast(entriesPerPage)); + uint32_t startPage = (page - 1) * static_cast(entriesPerPage); uint32_t endPage = startPage + static_cast(entriesPerPage); - query << "SELECT *, @row AS `entries`, " << page << " AS `page` FROM (SELECT *, (@row := @row + 1) AS `rn` FROM (SELECT `id`, `name`, `level`, `vocation`, `" - << categoryName << "` AS `points`, @curRank := IF(@prevRank = `" << categoryName << "`, @curRank, IF(@prevRank := `" << categoryName - << "`, @curRank + 1, @curRank + 1)) AS `rank` FROM `players` `p`, (SELECT @curRank := 0, @prevRank := NULL, @row := 0) `r` WHERE `group_id` < " - << static_cast(GROUP_TYPE_GAMEMASTER) << " ORDER BY `" << categoryName << "` DESC) `t`"; + Database& db = Database::getInstance(); + std::string escapedCategoryName = db.escapeString(categoryName); + + std::string query = fmt::format( + "SELECT `id`, `name`, `level`, `vocation`, `points`, `rank`, `entries`, {} AS `page` FROM (" + "SELECT `id`, `name`, `level`, `vocation`, `{}` AS `points`, " + "@curRank := IF(@prevRank = `{}`, @curRank, IF(@prevRank := `{}`, @curRank + 1, @curRank + 1)) AS `rank`, " + "(@row := @row + 1) AS `entries` FROM (" + "SELECT `id`, `name`, `level`, `vocation`, `{}` FROM `players` `p`, " + "(SELECT @curRank := 0, @prevRank := NULL, @row := 0) `r` " + "WHERE `group_id` < {} ORDER BY `{}` DESC" + ") `t`", + page, escapedCategoryName, escapedCategoryName, escapedCategoryName, escapedCategoryName, static_cast(GROUP_TYPE_GAMEMASTER), escapedCategoryName + ); if (vocation != 0xFFFFFFFF) { - query << generateVocationConditionHighscore(vocation); + query += generateVocationConditionHighscore(vocation); } - query << ") `T` WHERE `rn` > " << startPage << " AND `rn` <= " << endPage; - return query.str(); + query += fmt::format(") `T` WHERE `entries` > {} AND `entries` <= {}", startPage, endPage); + + return query; } std::string Game::generateHighscoreQueryForOurRank(const std::string &categoryName, uint8_t entriesPerPage, uint32_t playerGUID, uint32_t vocation) { - std::ostringstream query; + Database& db = Database::getInstance(); + std::string escapedCategoryName = db.escapeString(categoryName); std::string entriesStr = std::to_string(entriesPerPage); - query << "SELECT *, @row AS `entries`, (@ourRow DIV " << entriesStr << ") + 1 AS `page` FROM (SELECT *, (@row := @row + 1) AS `rn`, @ourRow := IF(`id` = " - << playerGUID << ", @row - 1, @ourRow) AS `rw` FROM (SELECT `id`, `name`, `level`, `vocation`, `" << categoryName << "` AS `points`, @curRank := IF(@prevRank = `" - << categoryName << "`, @curRank, IF(@prevRank := `" << categoryName << "`, @curRank + 1, @curRank + 1)) AS `rank` FROM `players` `p`, (SELECT @curRank := 0, @prevRank := NULL, @row := 0, @ourRow := 0) `r` WHERE `group_id` < " - << static_cast(GROUP_TYPE_GAMEMASTER) << " ORDER BY `" << categoryName << "` DESC) `t`"; + std::string query = fmt::format( + "SELECT `id`, `name`, `level`, `vocation`, `points`, `rank`, @row AS `entries`, " + "(@ourRow DIV {0}) + 1 AS `page` FROM (" + "SELECT `id`, `name`, `level`, `vocation`, `{1}` AS `points`, " + "@curRank := IF(@prevRank = `{1}`, @curRank, IF(@prevRank := `{1}`, @curRank + 1, @curRank + 1)) AS `rank`, " + "(@row := @row + 1) AS `rn`, @ourRow := IF(`id` = {2}, @row - 1, @ourRow) AS `rw` FROM (" + "SELECT `id`, `name`, `level`, `vocation`, `{1}` FROM `players` `p`, " + "(SELECT @curRank := 0, @prevRank := NULL, @row := 0, @ourRow := 0) `r` " + "WHERE `group_id` < {3} ORDER BY `{1}` DESC" + ") `t`", + entriesStr, escapedCategoryName, playerGUID, static_cast(GROUP_TYPE_GAMEMASTER) + ); if (vocation != 0xFFFFFFFF) { - query << generateVocationConditionHighscore(vocation); + query += generateVocationConditionHighscore(vocation); } - query << ") `T` WHERE `rn` > ((@ourRow DIV " << entriesStr << ") * " << entriesStr << ") AND `rn` <= (((@ourRow DIV " << entriesStr << ") * " << entriesStr << ") + " << entriesStr << ")"; - return query.str(); + query += fmt::format( + ") `T` WHERE `rn` > ((@ourRow DIV {0}) * {0}) AND `rn` <= (((@ourRow DIV {0}) * {0}) + {0})", + entriesStr + ); + + return query; } std::string Game::generateVocationConditionHighscore(uint32_t vocation) { diff --git a/src/io/functions/iologindata_load_player.cpp b/src/io/functions/iologindata_load_player.cpp index e724d0ceda9..21d251c6dbe 100644 --- a/src/io/functions/iologindata_load_player.cpp +++ b/src/io/functions/iologindata_load_player.cpp @@ -869,14 +869,18 @@ void IOLoginDataLoad::loadPlayerTaskHuntingClass(const std::shared_ptr & } void IOLoginDataLoad::loadPlayerForgeHistory(const std::shared_ptr &player, DBResult_ptr result) { - if (!result || !player) { - g_logger().warn("[{}] - Player or Result nullptr", __FUNCTION__); + if (!player) { + g_logger().warn("[{}] - Player nullptr", __FUNCTION__); return; } - std::ostringstream query; - query << "SELECT * FROM `forge_history` WHERE `player_id` = " << player->getGUID(); - if ((result = Database::getInstance().storeQuery(query.str()))) { + auto playerGUID = player->getGUID(); + + auto query = fmt::format( + "SELECT id, action_type, description, done_at, is_success FROM forge_history WHERE player_id = {}", + playerGUID + ); + if ((result = Database::getInstance().storeQuery(query))) { do { auto actionEnum = magic_enum::enum_value(result->getNumber("action_type")); ForgeHistory history; diff --git a/src/io/io_bosstiary.cpp b/src/io/io_bosstiary.cpp index 3e8a05524e6..534ee4e8072 100644 --- a/src/io/io_bosstiary.cpp +++ b/src/io/io_bosstiary.cpp @@ -21,9 +21,8 @@ IOBosstiary &IOBosstiary::getInstance() { void IOBosstiary::loadBoostedBoss() { Database &database = Database::getInstance(); - std::ostringstream query; - query << "SELECT * FROM `boosted_boss`"; - DBResult_ptr result = database.storeQuery(query.str()); + auto query = fmt::format("SELECT `date`, `boostname`, `raceid` FROM `boosted_boss`"); + DBResult_ptr result = database.storeQuery(query); if (!result) { g_logger().error("[{}] Failed to detect boosted boss database. (CODE 01)", __FUNCTION__); return; @@ -86,37 +85,49 @@ void IOBosstiary::loadBoostedBoss() { break; } - query.str(std::string()); - query << "UPDATE `boosted_boss` SET "; - query << "`date` = '" << today << "',"; - query << "`boostname` = " << database.escapeString(bossName) << ","; - if (const auto bossType = getMonsterTypeByBossRaceId(bossId); - bossType) { - query << "`looktypeEx` = " << static_cast(bossType->info.outfit.lookTypeEx) << ","; - query << "`looktype` = " << static_cast(bossType->info.outfit.lookType) << ","; - query << "`lookfeet` = " << static_cast(bossType->info.outfit.lookFeet) << ","; - query << "`looklegs` = " << static_cast(bossType->info.outfit.lookLegs) << ","; - query << "`lookhead` = " << static_cast(bossType->info.outfit.lookHead) << ","; - query << "`lookbody` = " << static_cast(bossType->info.outfit.lookBody) << ","; - query << "`lookaddons` = " << static_cast(bossType->info.outfit.lookAddons) << ","; - query << "`lookmount` = " << static_cast(bossType->info.outfit.lookMount) << ","; + query = fmt::format( + "UPDATE `boosted_boss` SET `date` = '{}', `boostname` = {}, `raceid` = '{}', ", + today, database.escapeString(bossName), bossId + ); + + if (const auto bossType = getMonsterTypeByBossRaceId(bossId); bossType) { + query += fmt::format( + "`looktypeEx` = {}, `looktype` = {}, `lookfeet` = {}, `looklegs` = {}, " + "`lookhead` = {}, `lookbody` = {}, `lookaddons` = {}, `lookmount` = {}, ", + static_cast(bossType->info.outfit.lookTypeEx), + static_cast(bossType->info.outfit.lookType), + static_cast(bossType->info.outfit.lookFeet), + static_cast(bossType->info.outfit.lookLegs), + static_cast(bossType->info.outfit.lookHead), + static_cast(bossType->info.outfit.lookBody), + static_cast(bossType->info.outfit.lookAddons), + static_cast(bossType->info.outfit.lookMount) + ); } - query << "`raceid` = '" << bossId << "'"; - if (!database.executeQuery(query.str())) { + + query += fmt::format("`raceid` = '{}'", bossId); + + if (!database.executeQuery(query)) { g_logger().error("[{}] Failed to detect boosted boss database. (CODE 03)", __FUNCTION__); return; } - query.str(std::string()); - query << "UPDATE `player_bosstiary` SET `bossIdSlotOne` = 0 WHERE `bossIdSlotOne` = " << bossId; - if (!database.executeQuery(query.str())) { + query = fmt::format( + "UPDATE `player_bosstiary` SET `bossIdSlotOne` = 0 WHERE `bossIdSlotOne` = {}", + bossId + ); + + if (!database.executeQuery(query)) { g_logger().error("[{}] Failed to reset players selected boss slot 1. (CODE 03)", __FUNCTION__); } - query.str(std::string()); - query << "UPDATE `player_bosstiary` SET `bossIdSlotTwo` = 0 WHERE `bossIdSlotTwo` = " << bossId; - if (!database.executeQuery(query.str())) { - g_logger().error("[{}] Failed to reset players selected boss slot 1. (CODE 03)", __FUNCTION__); + query = fmt::format( + "UPDATE `player_bosstiary` SET `bossIdSlotTwo` = 0 WHERE `bossIdSlotTwo` = {}", + bossId + ); + + if (!database.executeQuery(query)) { + g_logger().error("[{}] Failed to reset players selected boss slot 2. (CODE 03)", __FUNCTION__); } setBossBoostedName(bossName); From bdca921db2c4ceaef297e8dfbd6df48849d8caf2 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sat, 4 Jan 2025 04:07:25 +0000 Subject: [PATCH 2/3] Code format - (Clang-format) --- src/game/game.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/game.cpp b/src/game/game.cpp index 6638cad7cf2..b28f25dec5f 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -8511,7 +8511,7 @@ std::string Game::generateHighscoreQueryForEntries(const std::string &categoryNa uint32_t startPage = (page - 1) * static_cast(entriesPerPage); uint32_t endPage = startPage + static_cast(entriesPerPage); - Database& db = Database::getInstance(); + Database &db = Database::getInstance(); std::string escapedCategoryName = db.escapeString(categoryName); std::string query = fmt::format( @@ -8536,7 +8536,7 @@ std::string Game::generateHighscoreQueryForEntries(const std::string &categoryNa } std::string Game::generateHighscoreQueryForOurRank(const std::string &categoryName, uint8_t entriesPerPage, uint32_t playerGUID, uint32_t vocation) { - Database& db = Database::getInstance(); + Database &db = Database::getInstance(); std::string escapedCategoryName = db.escapeString(categoryName); std::string entriesStr = std::to_string(entriesPerPage); From 0a8635fcf6148eba9a4b43220d26a50e35aaf76e Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 5 Jan 2025 15:30:48 +0000 Subject: [PATCH 3/3] Code format - (Clang-format) --- src/io/io_bosstiary.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io/io_bosstiary.cpp b/src/io/io_bosstiary.cpp index 9b1b0c7745b..80634d11b42 100644 --- a/src/io/io_bosstiary.cpp +++ b/src/io/io_bosstiary.cpp @@ -116,7 +116,7 @@ void IOBosstiary::loadBoostedBoss() { if (!database.executeQuery(query)) { g_logger().error("[{}] Failed to reset players selected boss slot 2. (CODE 03)", __FUNCTION__); - return; + return; } setBossBoostedName(bossName);