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: Quan Zongliang <quanzongliang@gmail.com> Reviewed-by: Euler Taveira <euler.taveira@2ndquadrant.com> Discussion: https://www.postgresql.org/message-id/flat/c70fcab2-4866-0d9f-1d01-e75e189db342@gmail.com
This commit is contained in:
parent
a493f93342
commit
15cbbf81a5
@ -175,6 +175,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 */
|
||||
@ -10314,6 +10315,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).
|
||||
@ -10332,11 +10349,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10379,6 +10401,8 @@ RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
|
||||
indoid);
|
||||
tab->changedIndexDefs = lappend(tab->changedIndexDefs,
|
||||
defstring);
|
||||
|
||||
RememberReplicaIdentityForRebuilding(indoid, tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10593,6 +10617,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.
|
||||
|
25
src/backend/utils/cache/lsyscache.c
vendored
25
src/backend/utils/cache/lsyscache.c
vendored
@ -3156,3 +3156,28 @@ get_range_collation(Oid rangeOid)
|
||||
else
|
||||
return InvalidOid;
|
||||
}
|
||||
|
||||
/* ---------- PG_INDEX CACHE ---------- */
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
@ -178,6 +178,7 @@ extern char *get_namespace_name(Oid nspid);
|
||||
extern char *get_namespace_name_or_temp(Oid nspid);
|
||||
extern Oid get_range_subtype(Oid rangeOid);
|
||||
extern Oid get_range_collation(Oid rangeOid);
|
||||
extern bool get_index_isreplident(Oid index_oid);
|
||||
|
||||
#define type_is_array(typid) (get_element_type(typid) != InvalidOid)
|
||||
/* type_is_array_domain accepts both plain arrays and domains over arrays */
|
||||
|
@ -186,5 +186,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;
|
||||
|
@ -79,5 +79,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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user