XWikiHibernateVersioningStore.resetRCSArchive does three things inside a single Hibernate session:
getXWikiDocumentArchive loads the document's XWikiRCSNodeInfo entities with a JPA query, so they become managed entities of that session;
deleteArchive removes their rows with a bulk HQL delete, which bypasses the persistence context — the rows are gone, the entities are still in the session;
updateXWikiDocArchive rebuilds the archive with a single new node whose identifier is (docId, <the document's current version>) — necessarily one of the identifiers the session still holds — and calls session.saveOrUpdate on it.
Hence the NonUniqueObjectException reported here, on every document.
The body of resetRCSArchive has not changed since 2007 (git log -S), so the semantics of the reset — the history collapses to a single node, at the document's current version — are the intended ones. Only the consistency of the Hibernate session broke.
The fix
Evict the archive's nodes from the session before the bulk delete, along with their content when it has already been loaded (XWikiRCSNodeInfo and XWikiRCSNodeContent are two entities mapped on the samexwikircs row).
This covers the three call sites at once, since they all go through XWikiDocument.resetArchive: the reset action, the public API (Document.getDoc().resetArchive(...)) and the old importer's "reset history" option (plugin/packaging/Package.java) — so the two extra call sites carried over from XWIKI-21277 are fixed too.
Before / after
The History tab of a three-version document, right after calling the reset action. Before, the action fails with an HTTP 500 and the history is left untouched; after, the history holds the single remaining version.
Test
VersionIT#resetVersions in xwiki-platform-flamingo-skin-test-docker resets a three-version history and then resets the resulting one-version history again. Run twice with the same test code, checking with javap each time which xwiki-platform-oldcore jar the built WAR actually carried: it passes with the fix in the jar and fails without it, on assertFalse(historyTab.hasVersion("2.1")).
This message was sent by Atlassian Jira (v9.3.0#930000-sha1:287aeb6)
If image attachments aren't displayed, see this article.