Commit 1cc9c241 authored by Peter Eisentraut's avatar Peter Eisentraut

Preserve replica identity index across ALTER TABLE rewrite

If an index was explicitly set as replica identity index, this setting
was lost when a table was rewritten by ALTER TABLE.  Because this
setting is part of pg_index but actually controlled by ALTER
TABLE (not part of CREATE INDEX, say), we have to do some extra work
to restore it.
Based-on-patch-by: default avatarQuan Zongliang <quanzongliang@gmail.com>
Reviewed-by: default avatarEuler Taveira <euler.taveira@2ndquadrant.com>
Discussion: https://www.postgresql.org/message-id/flat/c70fcab2-4866-0d9f-1d01-e75e189db342@gmail.com
parent b7f64c64
......@@ -176,6 +176,7 @@ typedef struct AlteredTableInfo
List *changedConstraintDefs; /* string definitions of same */
List *changedIndexOids; /* OIDs of indexes to rebuild */
List *changedIndexDefs; /* string definitions of same */
char *replicaIdentityIndex; /* index to reset as REPLICA IDENTITY */
} AlteredTableInfo;
/* Struct describing one new constraint to check in Phase 3 scan */
......@@ -11562,6 +11563,22 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
return address;
}
/*
* Subroutine for ATExecAlterColumnType: remember that a replica identity
* needs to be reset.
*/
static void
RememberReplicaIdentityForRebuilding(Oid indoid, AlteredTableInfo *tab)
{
if (!get_index_isreplident(indoid))
return;
if (tab->replicaIdentityIndex)
elog(ERROR, "relation %u has multiple indexes marked as replica identity", tab->relid);
tab->replicaIdentityIndex = get_rel_name(indoid);
}
/*
* Subroutine for ATExecAlterColumnType: remember that a constraint needs
* to be rebuilt (which we might already know).
......@@ -11580,11 +11597,16 @@ RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab)
{
/* OK, capture the constraint's existing definition string */
char *defstring = pg_get_constraintdef_command(conoid);
Oid indoid;
tab->changedConstraintOids = lappend_oid(tab->changedConstraintOids,
conoid);
tab->changedConstraintDefs = lappend(tab->changedConstraintDefs,
defstring);
indoid = get_constraint_index(conoid);
if (OidIsValid(indoid))
RememberReplicaIdentityForRebuilding(indoid, tab);
}
}
......@@ -11627,6 +11649,8 @@ RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
indoid);
tab->changedIndexDefs = lappend(tab->changedIndexDefs,
defstring);
RememberReplicaIdentityForRebuilding(indoid, tab);
}
}
}
......@@ -11735,6 +11759,24 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
add_exact_object_address(&obj, objects);
}
/*
* Queue up command to restore replica identity index marking
*/
if (tab->replicaIdentityIndex)
{
AlterTableCmd *cmd = makeNode(AlterTableCmd);
ReplicaIdentityStmt *subcmd = makeNode(ReplicaIdentityStmt);
subcmd->identity_type = REPLICA_IDENTITY_INDEX;
subcmd->name = tab->replicaIdentityIndex;
cmd->subtype = AT_ReplicaIdentity;
cmd->def = (Node *) subcmd;
/* do it after indexes and constraints */
tab->subcmds[AT_PASS_OLD_CONSTR] =
lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
}
/*
* It should be okay to use DROP_RESTRICT here, since nothing else should
* be depending on these objects.
......
......@@ -3254,6 +3254,29 @@ get_index_column_opclass(Oid index_oid, int attno)
return opclass;
}
/*
* get_index_isreplident
*
* Given the index OID, return pg_index.indisreplident.
*/
bool
get_index_isreplident(Oid index_oid)
{
HeapTuple tuple;
Form_pg_index rd_index;
bool result;
tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
if (!HeapTupleIsValid(tuple))
return false;
rd_index = (Form_pg_index) GETSTRUCT(tuple);
result = rd_index->indisreplident;
ReleaseSysCache(tuple);
return result;
}
/*
* get_index_isvalid
*
......
......@@ -182,6 +182,7 @@ extern char *get_namespace_name_or_temp(Oid nspid);
extern Oid get_range_subtype(Oid rangeOid);
extern Oid get_range_collation(Oid rangeOid);
extern Oid get_index_column_opclass(Oid index_oid, int attno);
extern bool get_index_isreplident(Oid index_oid);
extern bool get_index_isvalid(Oid index_oid);
#define type_is_array(typid) (get_element_type(typid) != InvalidOid)
......
......@@ -179,5 +179,51 @@ SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass;
n
(1 row)
---
-- Test that ALTER TABLE rewrite preserves nondefault replica identity
---
-- constraint variant
CREATE TABLE test_replica_identity2 (id int UNIQUE NOT NULL);
ALTER TABLE test_replica_identity2 REPLICA IDENTITY USING INDEX test_replica_identity2_id_key;
\d test_replica_identity2
Table "public.test_replica_identity2"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
id | integer | | not null |
Indexes:
"test_replica_identity2_id_key" UNIQUE CONSTRAINT, btree (id) REPLICA IDENTITY
ALTER TABLE test_replica_identity2 ALTER COLUMN id TYPE bigint;
\d test_replica_identity2
Table "public.test_replica_identity2"
Column | Type | Collation | Nullable | Default
--------+--------+-----------+----------+---------
id | bigint | | not null |
Indexes:
"test_replica_identity2_id_key" UNIQUE CONSTRAINT, btree (id) REPLICA IDENTITY
-- straight index variant
CREATE TABLE test_replica_identity3 (id int NOT NULL);
CREATE UNIQUE INDEX test_replica_identity3_id_key ON test_replica_identity3 (id);
ALTER TABLE test_replica_identity3 REPLICA IDENTITY USING INDEX test_replica_identity3_id_key;
\d test_replica_identity3
Table "public.test_replica_identity3"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
id | integer | | not null |
Indexes:
"test_replica_identity3_id_key" UNIQUE, btree (id) REPLICA IDENTITY
ALTER TABLE test_replica_identity3 ALTER COLUMN id TYPE bigint;
\d test_replica_identity3
Table "public.test_replica_identity3"
Column | Type | Collation | Nullable | Default
--------+--------+-----------+----------+---------
id | bigint | | not null |
Indexes:
"test_replica_identity3_id_key" UNIQUE, btree (id) REPLICA IDENTITY
DROP TABLE test_replica_identity;
DROP TABLE test_replica_identity2;
DROP TABLE test_replica_identity3;
DROP TABLE test_replica_identity_othertable;
......@@ -75,5 +75,26 @@ SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass;
ALTER TABLE test_replica_identity REPLICA IDENTITY NOTHING;
SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass;
---
-- Test that ALTER TABLE rewrite preserves nondefault replica identity
---
-- constraint variant
CREATE TABLE test_replica_identity2 (id int UNIQUE NOT NULL);
ALTER TABLE test_replica_identity2 REPLICA IDENTITY USING INDEX test_replica_identity2_id_key;
\d test_replica_identity2
ALTER TABLE test_replica_identity2 ALTER COLUMN id TYPE bigint;
\d test_replica_identity2
-- straight index variant
CREATE TABLE test_replica_identity3 (id int NOT NULL);
CREATE UNIQUE INDEX test_replica_identity3_id_key ON test_replica_identity3 (id);
ALTER TABLE test_replica_identity3 REPLICA IDENTITY USING INDEX test_replica_identity3_id_key;
\d test_replica_identity3
ALTER TABLE test_replica_identity3 ALTER COLUMN id TYPE bigint;
\d test_replica_identity3
DROP TABLE test_replica_identity;
DROP TABLE test_replica_identity2;
DROP TABLE test_replica_identity3;
DROP TABLE test_replica_identity_othertable;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment