diff --git a/data/sql/updates/pending_db_characters/rev_1784315136456725704.sql b/data/sql/updates/pending_db_characters/rev_1784315136456725704.sql new file mode 100644 index 000000000..18c62ca8d --- /dev/null +++ b/data/sql/updates/pending_db_characters/rev_1784315136456725704.sql @@ -0,0 +1,10 @@ +-- petition_sign kept its (petitionguid, playerguid) primary key when the +-- petition_id schema stopped writing petitionguid: every row inserts with +-- petitionguid = 0, so the key collapses to (0, playerguid) and a character +-- can never hold more than one signature row overall (later signs fail +-- silently with a duplicate key on the async insert). +-- Re-key on (petition_id, playerguid) and drop the signature rows orphaned +-- by the type-filtered deletes that no longer match (`type` is not written +-- by the insert either). +DELETE `ps` FROM `petition_sign` `ps` LEFT JOIN `petition` `p` ON `p`.`petition_id` = `ps`.`petition_id` WHERE `p`.`petition_id` IS NULL; +ALTER TABLE `petition_sign` DROP PRIMARY KEY, ADD PRIMARY KEY (`petition_id`, `playerguid`), DROP INDEX `idx_petition_id_player`; diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index be215d322..939dd0919 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -272,7 +272,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() // Petitions PrepareStatement(CHAR_DEL_ALL_PETITION_SIGNATURES, "DELETE FROM petition_sign WHERE playerguid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_PETITION_SIGNATURE, "DELETE FROM petition_sign WHERE playerguid = ? AND type = ?", CONNECTION_ASYNC); + // petition_sign.type is not written by the sign insert (petition_id schema), join petition for the type filter + PrepareStatement(CHAR_DEL_PETITION_SIGNATURE, "DELETE ps FROM petition_sign ps INNER JOIN petition p ON p.petition_id = ps.petition_id WHERE ps.playerguid = ? AND p.type = ?", CONNECTION_ASYNC); // Arena teams PrepareStatement(CHAR_INS_ARENA_TEAM, "INSERT INTO arena_team (arenaTeamId, name, captainGuid, type, rating, backgroundColor, emblemStyle, emblemColor, borderStyle, borderColor) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); @@ -534,7 +535,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_PETITION_BY_OWNER, "DELETE FROM petition WHERE ownerguid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_OWNER, "DELETE FROM petition_sign WHERE ownerguid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PETITION_BY_OWNER_AND_TYPE, "DELETE FROM petition WHERE ownerguid = ? AND type = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_OWNER_AND_TYPE, "DELETE FROM petition_sign WHERE ownerguid = ? AND type = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_OWNER_AND_TYPE, "DELETE ps FROM petition_sign ps INNER JOIN petition p ON p.petition_id = ps.petition_id WHERE ps.ownerguid = ? AND p.type = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_GLYPHS, "INSERT INTO character_glyphs VALUES(?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_TALENT_BY_SPELL, "DELETE FROM character_talent WHERE guid = ? AND spell = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_TALENT, "INSERT INTO character_talent (guid, spell, specMask) VALUES (?, ?, ?)", CONNECTION_ASYNC);