| From: | Chao Li <li(dot)evan(dot)chao(at)gmail(dot)com> |
|---|---|
| To: | Matthias van de Meent <boekewurm+postgres(at)gmail(dot)com> |
| Cc: | Nathan Bossart <nathandbossart(at)gmail(dot)com>, pgsql-hackers(at)postgresql(dot)org, alvherre(at)kurilemu(dot)de |
| Subject: | Re: REPACK (CONCURRENTLY) fails when replica identity index is dropped |
| Date: | 2026-08-28 06:04:15 |
| Message-ID: | 54DABC65-787E-4DA9-895C-140A3CF862CF@gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
> On Aug 28, 2026, at 03:31, Matthias van de Meent <boekewurm+postgres(at)gmail(dot)com> wrote:
>
> On Thu, 27 Aug 2026 at 20:26, Nathan Bossart <nathandbossart(at)gmail(dot)com> wrote:
>>
>> I don't fully understand the mechanics of this one, but here is a
>> reproducer:
>>
>> CREATE TABLE t (a INT PRIMARY KEY, b INT, c TEXT);
>> INSERT INTO t SELECT g, g, repeat('x', 1000) FROM generate_series(1, 1000000) g;
>> CREATE UNIQUE INDEX i ON t (a);
>> ALTER TABLE t REPLICA IDENTITY USING INDEX i;
>> DROP INDEX i;
>> REPACK (CONCURRENTLY) t;
>>
>> -- in a separate session, while REPACK is still running
>> DELETE FROM t WHERE a = 1;
>>
>> This produces the following ERROR from the REPACK command:
>>
>> ERROR: incomplete delete info
>> CONTEXT: slot "pg_repack_34213", output plugin "pgrepack", in the change callback, associated LSN 0/A6CC1ED0
>> REPACK decoding worker
>>
>> I think this can be addressed by verifying the index exists in
>> check_concurrent_repack_requirements() and erroring out if it doesn't.
>
> I think the issue is caused by the following: REPACK's check has the
> incorrect assumption that REPLICA IDENTITY USING INDEX either reverts
> to DEFAULT or falls back to the behaviour of DEFAULT if the identity
> index gets dropped, and thus uses GetRelationIdentityOrPK(), which
> hides a lack of replica identity index. The issue shows up due to the
> following garden path of data flows:
>
> 1. A table with REPLICA IDENTITY USING INDEX doesn't fall back to
> REPLICA IDENTITY DEFAULT once the identity index is dropped.
> 2. In the catcache, the table won't fall back to rd_replidindex =
> pkeyIndex when replident='i', but instead will set
> rd_replidindex=InvalidOid.
> See the tail end of RelationGetIndexList.
> 3. Then, in heap_delete, it calls ExtractReplicaIdentity() to find the
> key of the deleted tuple.
> 3a. ExtractR_I_() checks the identity key attributes from
> RelationGetIndexAttrBitmap(..., INDEX_ATTR_BITMAP_IDENTITY_KEY), which
> also only uses rd_replidindex, and doesn't fall back to the primary
> key index's attributes.
> 3b. If ExtractR_I_() doesn't have identity key attributes, it returns NULL
> 3c. heap_delete thus doesn't have any logical identity attributes to
> log, and treats the delete operation as any non-logical deletion when
> logging the data.
> 4. Finally, the DELETE record gets decoded, and the logical plugin
> finds out that no logical key data was included, and promptly ERRORs
> out.
>
> The attached patch is a blind shot that I suspect will fix the issue.
>
>
> Kind regards,
>
> Matthias van de Meent
> Databricks (https://www.databricks.com)
> <v1-0001-Repack-Fix-replica-identity-index-check.patch>
After dropping the index, pg_class.relreplident is still 'i', but the corresponding pg_index entry is deleted, so the table is left in a stale state. If we only check whether the REPLICA IDENTITY index is valid in REPACK, that prevents REPACK from starting, but doesn’t resolve the stale state itself.
We cannot assume the intended replacement replica identity after removing an explicitly selected index. For example, the user might want DEFAULT, FULL, or maybe another index. Should we instead prevent dropping of an index while it is used as REPLICA IDENTITY?
The attached diff makes a change in the direction, like this:
```
evantest=# CREATE TABLE t (a INT PRIMARY KEY, b INT, c TEXT);
CREATE TABLE
evantest=# CREATE UNIQUE INDEX i ON t (a);
CREATE INDEX
evantest=# ALTER TABLE t REPLICA IDENTITY USING INDEX i;
ALTER TABLE
evantest=# DROP INDEX i;
ERROR: cannot drop index "i" because it is used as replica identity
HINT: Use ALTER TABLE ... REPLICA IDENTITY to change the table's replica identity first.
```
Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/
| Attachment | Content-Type | Size |
|---|---|---|
| block_drop_index.diff | application/octet-stream | 3.8 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Ian Lawrence Barwick | 2026-08-28 06:07:58 | Re: [PATCH] doc: clarify AS requirement when VALUES used in a FROM clause |
| Previous Message | Tender Wang | 2026-08-28 05:55:25 | Re: Unsafe qual pushdown through DISTINCT with simple CASE expressions |