fix: restore ALTER INDEX ... ATTACH PARTITION with indices and constraints - #1094
Merged
Merged
Conversation
…aints parseDump classifies dump lines by prefix, and `ALTER INDEX ... ATTACH PARTITION` matches none of the special cases, so it falls through to the default and lands in the filtered segment. That segment is restored before indicesAndConstraints, where the parent index is created, so every attach fails with "relation does not exist". The error is bucketed as ignorable and never retried, leaving the parent index indisvalid on the target. For a partitioned table's PRIMARY KEY that is more than a missing index: an invalid index is not usable as a constraint, so the table has no key on the target, hence no replica identity for UPDATE/DELETE and no conflict target for INSERT — buildOnConflictQuery returns "" without primary key columns. With strict_mode false those changes are then dropped and the checkpoint advanced, so a load that reports success produces a table that silently stops replicating. Routing the statement into indicesAndConstraints puts it after the CREATE INDEX it depends on, which pg_dump already emits first. Verified against the reproduction in xataio#1093: a partitioned table with a primary key and a secondary index, snapshotted into an empty target. Before, 5 ignored errors and both partitioned indexes invalid; after, no "does not exist" errors, `pg_index WHERE NOT indisvalid` empty, all rows present.
kvch
approved these changes
Aug 19, 2026
kvch
enabled auto-merge (squash)
August 19, 2026 19:05
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.
Fixes the partitioned-index half of #1093.
The problem
parseDumpclassifies dump lines by prefix.ALTER INDEX … ATTACH PARTITIONmatches none of the special cases — it starts withALTER INDEX, notALTER TABLEorCREATE INDEX— so it falls through todefaultand lands in thefilteredsegment. That segment is restored beforeindicesAndConstraints, where the parent index is created, so every attach fails withrelation does not exist. The error is bucketed as ignorable and never retried, and the parent index staysindisvalid = falseon the target.Why it is worth fixing beyond the index
An invalid index is not usable as a constraint either, so a partitioned table's
PRIMARY KEYdoes not exist on the target. That means:buildOnConflictQueryreturns""when there are no primary key columns;strict_mode: false, those changes are dropped and the checkpoint advanced.So a load that reports success leaves a table that silently stops replicating. We hit this on a JFrog Artifactory schema, where
jfbus_eventsis partitioned; the only trace was one line ofrestore: N errors ignored.The change
Route the statement into
indicesAndConstraints, which puts it after theCREATE INDEXit depends on — pg_dump already emits the parent index first, so ordering within the segment is preserved. Kept narrow: no change to error classification, though as noted on the issue that is the reason both this and the extension case were invisible, and I would be glad to follow up separately if you want it.Verification
Unit test added alongside the existing
parseDumpcases: it asserts the table attachment stays infiltered, the index attachment moves toindicesAndConstraints, and that it lands after the parentCREATE INDEX.End to end, against the reproduction from #1093 — a partitioned table with a primary key and a secondary index, snapshotted into an empty target:
does not existdoes not existpg_index WHERE NOT indisvalidjfbus_events_pkey,jfbus_events_topic_partition_event_idgo test ./pkg/snapshot/...passes.