Repository navigation
Move the tag rows when archiving a stream under archived-stream partitioning - #5679
Merged
Merged
Conversation
…am partitioning With UseArchivedStreamPartitioning on and any DCB tag type registered, ArchiveStream on a stream with tagged events came back as 23503. Each mt_event_tag_* table is itself partitioned by is_archived and carries a composite foreign key (seq_id, is_archived) to mt_events, which is not deferrable. The issue describes the cause as a rejected UPDATE, but under partitioning mt_archive_stream does not update is_archived at all: it inserts the rows into the archived partition and DELETES the originals. So it is the delete that is refused, with the tag rows still pointing at the (seq_id, FALSE) rows it is removing. That also means ON UPDATE CASCADE would not have helped, and no schema migration is needed. mt_archive_stream now moves the tag rows with their events, and the statement ORDER is the whole fix, because every statement has to leave both sides of that key consistent on its own: 1. the archived event rows are inserted first, so (seq_id, TRUE) exists to point at; 2. then the archived tag rows, which reference it; 3. then the original tag rows are deleted, BEFORE the events they still reference; 4. and only then the original event rows. Statements are emitted for every registered tag type, with an explicit column list for the same reason #4619 made the event and stream inserts explicit. Nothing is emitted in HStore mode, where tags live inline on mt_events.tags and travel with the row, and the tenant predicate is written against an alias because both the tag table and mt_events carry tenant_id under conjoined tenancy. The non-partitioned path is untouched: it updates is_archived in place, seq_id does not change, and the plain foreign key is undisturbed. Six tests: the move itself, two tag tables, conjoined tenancy with the same stream id and tag value in two tenants, an untagged stream beside a registered tag type, and HStore mode. Four of the six fail on master with the reported 23503. The sixth pins something this does NOT fix: tag queries return archived events, where every other event query excludes them. Verified independent of this change -- the same answers come back with partitioning off -- and filed as #5677. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01481eiEZg1Bv6pu4DrgPRg3
Member
Author
|
Also ran |
This was referenced Oct 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #5675.
A correction to the cause
The issue describes
mt_archive_streamas runningupdate mt_events set is_archived = TRUEand the FK rejecting that update. That is the non-partitioned path, and it is fine:seq_iddoes not change, so the plainseq_idforeign key is undisturbed.Under
UseArchivedStreamPartitioningthe function does something else entirely — it inserts the rows into the archived partition and deletes the originals. So the statement being refused is thedelete from mt_events … is_archived = FALSE, with the tag rows still pointing at the(seq_id, FALSE)rows it is removing:Two things follow.
ON UPDATE CASCADE(the issue's second fix option) would not have helped, because nothing updates the referenced key. And no schema migration is needed — only the function body changes, which Weasel regenerates on its own.The fix
mt_archive_streammoves the tag rows with their events. The composite FK is not deferrable, so the statement order is the whole fix — every statement has to leave both sides of the key consistent by itself:(seq_id, TRUE)exists to point at;Details worth knowing:
ALTER TABLE ADD COLUMNon an existing tag table appends physically, and a positional insert would then load the wrong column.mt_events.tagsand travel with the row, so the function must not reference a tag table that does not exist.mt_eventscarrytenant_idunder conjoined tenancy and an unqualified column in the subquery would bind to the inner table.Tests
Bug_5675_archiving_a_tagged_stream, 6 tests:archiving_a_tagged_stream_moves_its_tag_rowsarchiving_moves_every_registered_tag_table..._under_conjoined_tenancy_leaves_other_tenants_alonean_untagged_stream_beside_a_registered_tag_type_still_archivesarchiving_a_tagged_stream_in_hstore_mode_still_worksa_tag_query_still_sees_the_archived_events_which_is_a_separate_bugA/B against the unfixed code: 4 of the 6 fail with exactly the reported
23503. The two that pass are the untagged and HStore cases, which should pass both ways. With the fix: 6/6.Full
EventSourcingTestson net10.0: 2540 passed, 27 skipped, 0 failed.What this does NOT fix: #5677
The issue's "tests to add" asks that tag queries "behave as documented" for archived events afterwards. They do not behave like any other event query:
QueryAllRawEvents()QueryByTagsAsyncEventsExistAsyncI verified that is independent of this change: the same two answers come back with
UseArchivedStreamPartitioningoff, which the archive function change never touches, and in both storage modes. So it is pre-existing and filed separately as #5677 — it matters most forEventsExistAsync, which is what a DCB boundary assertion is built on.The sixth test pins the current answers and names that issue, so the behaviour is written down rather than rediscovered. It should be inverted when #5677 is fixed.
Follow-up this unblocks
tombstoning_streams.tombstoning_deletes_tag_rows_in_a_partitioned_tag_table(from #5674) carries a comment saying it deliberately does not archive first because of this bug. It can archive now; I left it alone to keep this diff to the fix.🤖 Generated with Claude Code
https://claude.ai/code/session_01481eiEZg1Bv6pu4DrgPRg3