Skip inserting rows that would cause a duplicate primary key error.

The cause is that somehow, during regular play, MP campaigns can end up with duplicate values in the [content] data for each [addon]. A very similar issue was fixed in 6c980d1, but there's apparently some other way to trigger it that I haven't been able to reproduce. Since the error itself is harmless, it'll just be avoided server-side to avoid the spurious errors in the server log file.
This commit is contained in:
Pentarctagon 2023-01-06 11:01:55 -06:00
parent b8393c49d1
commit 2c3e674e89
2 changed files with 13 additions and 8 deletions

View file

@ -1681,11 +1681,16 @@ void server::handle_player_in_game(player_iterator p, simple_wml::document& data
const simple_wml::node& m = *g.level().root().child("multiplayer");
DBG_SERVER << simple_wml::node_to_string(m) << '\n';
// [addon] info handling
std::set<std::string> primary_keys;
for(const auto& addon : m.children("addon")) {
for(const auto& content : addon->children("content")) {
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";
std::string key = uuid_+"-"+std::to_string(g.db_id())+"-"+content->attr("type").to_string()+"-"+content->attr("id").to_string()+"-"+addon->attr("id").to_string();
if(primary_keys.count(key) == 0) {
primary_keys.emplace(key);
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";
}
}
}
}

View file

@ -108,7 +108,7 @@ create table game_player_info
CREATE INDEX USER_ID_IDX ON game_player_info(USER_ID);
-- information about the scenario/era/modifications for the game
-- TYPE: one of era/scenario/modification
-- TYPE: one of era/scenario/modification/campaign
-- ID: the id of the content
-- NAME: the content's user-visible name
-- SOURCE: the id of the add-on that the particular content came from
@ -117,12 +117,12 @@ create table game_content_info
(
INSTANCE_UUID CHAR(36) NOT NULL,
GAME_ID INT UNSIGNED NOT NULL,
TYPE VARCHAR(255) NOT NULL,
ID VARCHAR(255) NOT NULL,
TYPE VARCHAR(100) NOT NULL,
ID VARCHAR(100) NOT NULL,
NAME VARCHAR(255),
SOURCE VARCHAR(255) NOT NULL,
SOURCE VARCHAR(100) NOT NULL,
VERSION VARCHAR(255) NOT NULL,
PRIMARY KEY (INSTANCE_UUID, GAME_ID, TYPE, ID)
PRIMARY KEY (INSTANCE_UUID, GAME_ID, TYPE, ID, SOURCE)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- information about an uploaded addon