From a719b8d74425314650f52bd582e0a62fc8580a16 Mon Sep 17 00:00:00 2001 From: Pentarctagon Date: Wed, 10 Nov 2021 10:34:46 -0600 Subject: [PATCH] Check for potential duplicates before inserting. --- src/server/common/dbconn.cpp | 22 +++++++++++++++++++--- src/server/common/dbconn.hpp | 13 ++++++++++++- src/server/common/forum_user_handler.cpp | 4 ++-- src/server/common/forum_user_handler.hpp | 3 ++- src/server/common/user_handler.hpp | 2 +- src/server/wesnothd/server.cpp | 5 ++++- 6 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/server/common/dbconn.cpp b/src/server/common/dbconn.cpp index 447ee871de7..efdcab82481 100644 --- a/src/server/common/dbconn.cpp +++ b/src/server/common/dbconn.cpp @@ -325,16 +325,17 @@ void dbconn::insert_game_player_info(const std::string& uuid, int game_id, const log_sql_exception("Failed to insert game player info row for UUID `"+uuid+"` and game ID `"+std::to_string(game_id)+"`", e); } } -void dbconn::insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& source, const std::string& version) +unsigned long long dbconn::insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& source, const std::string& version) { try { - modify(connection_, "INSERT INTO `"+db_game_content_info_table_+"`(INSTANCE_UUID, GAME_ID, TYPE, NAME, ID, SOURCE, VERSION) VALUES(?, ?, ?, ?, ?, ?, ?)", + return modify(connection_, "INSERT INTO `"+db_game_content_info_table_+"`(INSTANCE_UUID, GAME_ID, TYPE, NAME, ID, SOURCE, VERSION) VALUES(?, ?, ?, ?, ?, ?, ?)", uuid, game_id, type, name, id, source, version); } catch(const mariadb::exception::base& e) { log_sql_exception("Failed to insert game content info row for UUID `"+uuid+"` and game ID `"+std::to_string(game_id)+"`", e); + return 0; } } void dbconn::set_oos_flag(const std::string& uuid, int game_id) @@ -380,7 +381,7 @@ unsigned long long dbconn::insert_login(const std::string& username, const std:: { try { - return modify(connection_, "INSERT INTO `"+db_connection_history_table_+"`(USER_NAME, IP, VERSION) values(lower(?), ?, ?)", + return modify_get_id(connection_, "INSERT INTO `"+db_connection_history_table_+"`(USER_NAME, IP, VERSION) values(lower(?), ?, ?)", username, ip, version); } catch(const mariadb::exception::base& e) @@ -531,6 +532,21 @@ mariadb::result_set_ref dbconn::select(mariadb::connection_ref connection, const } template unsigned long long dbconn::modify(mariadb::connection_ref connection, const std::string& sql, Args&&... args) +{ + try + { + mariadb::statement_ref stmt = query(connection, sql, args...); + unsigned long long count = stmt->execute(); + return count; + } + catch(const mariadb::exception::base& e) + { + ERR_SQL << "SQL query failed for query: `"+sql+"`" << std::endl; + throw e; + } +} +template +unsigned long long dbconn::modify_get_id(mariadb::connection_ref connection, const std::string& sql, Args&&... args) { try { diff --git a/src/server/common/dbconn.hpp b/src/server/common/dbconn.hpp index 3731e787ed8..9269bf93153 100644 --- a/src/server/common/dbconn.hpp +++ b/src/server/common/dbconn.hpp @@ -137,7 +137,7 @@ class dbconn /** * @see forum_user_handler::db_insert_game_content_info(). */ - void insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& source, const std::string& version); + unsigned long long insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& source, const std::string& version); /** * @see forum_user_handler::db_set_oos_flag(). @@ -283,6 +283,17 @@ class dbconn template unsigned long long modify(mariadb::connection_ref connection, const std::string& sql, Args&&... args); + /** + * Executes non-select statements (ie: insert, update, delete), but primarily intended for inserts that return a generated ID. + * + * @param connection The database connecion that will be used to execute the query. + * @param sql The SQL text to be executed. + * @param args The parameterized values to be inserted into the query. + * @return The value of an AUTO_INCREMENT column on the table being modified. + */ + template + unsigned long long modify_get_id(mariadb::connection_ref connection, const std::string& sql, Args&&... args); + /** * Begins recursively unpacking of the parameter pack in order to be able to call the correct parameterized setters on the query. * diff --git a/src/server/common/forum_user_handler.cpp b/src/server/common/forum_user_handler.cpp index a56cc37de5c..01b4012bdbe 100644 --- a/src/server/common/forum_user_handler.cpp +++ b/src/server/common/forum_user_handler.cpp @@ -219,8 +219,8 @@ void fuh::db_insert_game_player_info(const std::string& uuid, int game_id, const conn_.insert_game_player_info(uuid, game_id, username, side_number, is_host, faction, version, source, current_user); } -void fuh::db_insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& source, const std::string& version){ - conn_.insert_game_content_info(uuid, game_id, type, name, id, source, version); +unsigned long long fuh::db_insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& source, const std::string& version){ + return conn_.insert_game_content_info(uuid, game_id, type, name, id, source, version); } void fuh::db_set_oos_flag(const std::string& uuid, int game_id){ diff --git a/src/server/common/forum_user_handler.hpp b/src/server/common/forum_user_handler.hpp index fa92bfdf073..245efec44e2 100644 --- a/src/server/common/forum_user_handler.hpp +++ b/src/server/common/forum_user_handler.hpp @@ -180,8 +180,9 @@ public: * @param id The id of the content. * @param source The source add-on for the content. * @param version The version of the source add-on. + * @return The number of rows inserted which should always be 1. */ - void db_insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& source, const std::string& version); + unsigned long long db_insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& source, const std::string& version); /** * Sets the OOS flag in the database if wesnothd is told by a client it has detected an OOS error. diff --git a/src/server/common/user_handler.hpp b/src/server/common/user_handler.hpp index 16dfd4966c2..5af00707dc1 100644 --- a/src/server/common/user_handler.hpp +++ b/src/server/common/user_handler.hpp @@ -140,7 +140,7 @@ public: virtual void db_insert_game_info(const std::string& uuid, int game_id, const std::string& version, const std::string& name, int reload, int observers, int is_public, int has_password) = 0; virtual void db_update_game_end(const std::string& uuid, int game_id, const std::string& replay_location) = 0; virtual void db_insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user) = 0; - virtual void db_insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& source, const std::string& version) = 0; + virtual unsigned long long db_insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& source, const std::string& version) = 0; virtual void db_set_oos_flag(const std::string& uuid, int game_id) = 0; virtual void async_test_query(boost::asio::io_service& io_service, int limit) = 0; virtual bool db_topic_id_exists(int topic_id) = 0; diff --git a/src/server/wesnothd/server.cpp b/src/server/wesnothd/server.cpp index 49d8a112a71..cd5458df6d3 100644 --- a/src/server/wesnothd/server.cpp +++ b/src/server/wesnothd/server.cpp @@ -1688,7 +1688,10 @@ void server::handle_player_in_game(player_iterator p, simple_wml::document& data // [addon] info handling for(const auto& addon : m.children("addon")) { for(const auto& content : addon->children("content")) { - user_handler_->db_insert_game_content_info(uuid_, g.db_id(), content->attr("type").to_string(), content->attr("name").to_string(), content->attr("id").to_string(), addon->attr("id").to_string(), addon->attr("version").to_string()); + unsigned long long rows_inserted = user_handler_->db_insert_game_content_info(uuid_, g.db_id(), content->attr("type").to_string(), content->attr("name").to_string(), content->attr("id").to_string(), addon->attr("id").to_string(), addon->attr("version").to_string()); + if(rows_inserted == 0) { + WRN_SERVER << "Did not insert content row for [addon] data with uuid '" << uuid_ <<"', game ID '" << g.db_id() << "', type '" << content->attr("type").to_string() << "', and content ID '" << content->attr("id").to_string() << "'\n"; + } } }