mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
Disallow REPACK (CONCURRENTLY) when replica identity index is dropped
The replica identity determination was "flawed": it fell back to the primary key if the marked index was dropped, which is a defensible choice, but logical decoding has a differing opinion and fails to provide usable tuple identity data in this case. "Fix" REPACK by refusing to use the primary key in that case. This is arguably broken behavior in RelationGetIndexList, but I'll refrain from changing that at this stage. Reported-by: Nathan Bossart <nathandbossart@gmail.com> Author: Matthias van de Meent <boekewurm+postgres@gmail.com> Author: Ewan Young <kdbase.hack@gmail.com> Backpatch-through: 19 Discussion: https://postgr.es/m/apCBRKCH8jwKiaSY@nathan
This commit is contained in:
@@ -111,6 +111,16 @@ REPACK (CONCURRENTLY) repack_conc_replident;
|
||||
ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_replident"
|
||||
DETAIL: This operation does not support deferrable primary keys.
|
||||
HINT: Use ALTER TABLE ... REPLICA IDENTITY USING INDEX to designate another index as replica identity.
|
||||
-- Doesn't support tables whose replica identity indexes were dropped, even
|
||||
-- if a workable primary key is present.
|
||||
ALTER TABLE repack_conc_replident DROP CONSTRAINT repack_conc_replident_pkey,
|
||||
ADD PRIMARY KEY (i);
|
||||
CREATE UNIQUE INDEX replidx ON repack_conc_replident (i);
|
||||
ALTER TABLE repack_conc_replident REPLICA IDENTITY USING INDEX replidx;
|
||||
DROP INDEX replidx;
|
||||
REPACK (CONCURRENTLY) repack_conc_replident;
|
||||
ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_replident"
|
||||
DETAIL: Relation "repack_conc_replident" has no identity index.
|
||||
-- clean up
|
||||
DROP TABLE repack_conc_replident, clstrpart;
|
||||
-- verify that the pgrepack plugin cannot be called directly
|
||||
|
||||
@@ -83,6 +83,15 @@ REPACK (CONCURRENTLY) repack_conc_replident;
|
||||
ALTER TABLE repack_conc_replident ADD PRIMARY KEY (i) DEFERRABLE;
|
||||
REPACK (CONCURRENTLY) repack_conc_replident;
|
||||
|
||||
-- Doesn't support tables whose replica identity indexes were dropped, even
|
||||
-- if a workable primary key is present.
|
||||
ALTER TABLE repack_conc_replident DROP CONSTRAINT repack_conc_replident_pkey,
|
||||
ADD PRIMARY KEY (i);
|
||||
CREATE UNIQUE INDEX replidx ON repack_conc_replident (i);
|
||||
ALTER TABLE repack_conc_replident REPLICA IDENTITY USING INDEX replidx;
|
||||
DROP INDEX replidx;
|
||||
REPACK (CONCURRENTLY) repack_conc_replident;
|
||||
|
||||
-- clean up
|
||||
DROP TABLE repack_conc_replident, clstrpart;
|
||||
|
||||
|
||||
@@ -971,13 +971,11 @@ check_concurrent_repack_requirements(Relation rel, Oid *ident_idx_p)
|
||||
"REPLICA IDENTITY NOTHING" : "REPLICA IDENTITY FULL"));
|
||||
|
||||
/*
|
||||
* Obtain the replica identity index -- either one that has been set
|
||||
* explicitly, or a non-deferrable primary key. If none of these cases
|
||||
* apply, the table cannot be repacked concurrently. It might be possible
|
||||
* to have repack work with a FULL replica identity; however that requires
|
||||
* more work and is not implemented yet.
|
||||
* Obtain the replica identity index to use. If there isn't one, the
|
||||
* table cannot be repacked concurrently. (Replica identity FULL is not
|
||||
* supported yet.)
|
||||
*/
|
||||
ident_idx = GetRelationIdentityOrPK(rel);
|
||||
ident_idx = RelationGetReplicaIndex(rel);
|
||||
if (!OidIsValid(ident_idx))
|
||||
{
|
||||
/* This special case warrants its own error message */
|
||||
|
||||
7
src/backend/utils/cache/relcache.c
vendored
7
src/backend/utils/cache/relcache.c
vendored
@@ -5075,6 +5075,13 @@ RelationGetPrimaryKeyIndex(Relation relation, bool deferrable_ok)
|
||||
/*
|
||||
* RelationGetReplicaIndex -- get OID of the relation's replica identity index
|
||||
*
|
||||
* If replica identity is DEFAULT, then return the OID of the primary key, if
|
||||
* it's not deferrable; if replica identity is INDEX, return the OID of the
|
||||
* index with indisreplident, if one exists.
|
||||
*
|
||||
* Note that a working PK is not returned if identity is INDEX! This is
|
||||
* surprising if the replica identity index is dropped. FIXME someday.
|
||||
*
|
||||
* Returns InvalidOid if there is no such index.
|
||||
*/
|
||||
Oid
|
||||
|
||||
Reference in New Issue
Block a user