Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1cc9c24

Browse files
committed
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
1 parent b7f64c6 commit 1cc9c24

File tree

5 files changed

+133
-0
lines changed

5 files changed

+133
-0
lines changed

src/backend/commands/tablecmds.c

+42
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ typedef struct AlteredTableInfo
176176
List *changedConstraintDefs; /* string definitions of same */
177177
List *changedIndexOids; /* OIDs of indexes to rebuild */
178178
List *changedIndexDefs; /* string definitions of same */
179+
char *replicaIdentityIndex; /* index to reset as REPLICA IDENTITY */
179180
} AlteredTableInfo;
180181

181182
/* Struct describing one new constraint to check in Phase 3 scan */
@@ -11562,6 +11563,22 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
1156211563
return address;
1156311564
}
1156411565

11566+
/*
11567+
* Subroutine for ATExecAlterColumnType: remember that a replica identity
11568+
* needs to be reset.
11569+
*/
11570+
static void
11571+
RememberReplicaIdentityForRebuilding(Oid indoid, AlteredTableInfo *tab)
11572+
{
11573+
if (!get_index_isreplident(indoid))
11574+
return;
11575+
11576+
if (tab->replicaIdentityIndex)
11577+
elog(ERROR, "relation %u has multiple indexes marked as replica identity", tab->relid);
11578+
11579+
tab->replicaIdentityIndex = get_rel_name(indoid);
11580+
}
11581+
1156511582
/*
1156611583
* Subroutine for ATExecAlterColumnType: remember that a constraint needs
1156711584
* to be rebuilt (which we might already know).
@@ -11580,11 +11597,16 @@ RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab)
1158011597
{
1158111598
/* OK, capture the constraint's existing definition string */
1158211599
char *defstring = pg_get_constraintdef_command(conoid);
11600+
Oid indoid;
1158311601

1158411602
tab->changedConstraintOids = lappend_oid(tab->changedConstraintOids,
1158511603
conoid);
1158611604
tab->changedConstraintDefs = lappend(tab->changedConstraintDefs,
1158711605
defstring);
11606+
11607+
indoid = get_constraint_index(conoid);
11608+
if (OidIsValid(indoid))
11609+
RememberReplicaIdentityForRebuilding(indoid, tab);
1158811610
}
1158911611
}
1159011612

@@ -11627,6 +11649,8 @@ RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
1162711649
indoid);
1162811650
tab->changedIndexDefs = lappend(tab->changedIndexDefs,
1162911651
defstring);
11652+
11653+
RememberReplicaIdentityForRebuilding(indoid, tab);
1163011654
}
1163111655
}
1163211656
}
@@ -11735,6 +11759,24 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
1173511759
add_exact_object_address(&obj, objects);
1173611760
}
1173711761

11762+
/*
11763+
* Queue up command to restore replica identity index marking
11764+
*/
11765+
if (tab->replicaIdentityIndex)
11766+
{
11767+
AlterTableCmd *cmd = makeNode(AlterTableCmd);
11768+
ReplicaIdentityStmt *subcmd = makeNode(ReplicaIdentityStmt);
11769+
11770+
subcmd->identity_type = REPLICA_IDENTITY_INDEX;
11771+
subcmd->name = tab->replicaIdentityIndex;
11772+
cmd->subtype = AT_ReplicaIdentity;
11773+
cmd->def = (Node *) subcmd;
11774+
11775+
/* do it after indexes and constraints */
11776+
tab->subcmds[AT_PASS_OLD_CONSTR] =
11777+
lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
11778+
}
11779+
1173811780
/*
1173911781
* It should be okay to use DROP_RESTRICT here, since nothing else should
1174011782
* be depending on these objects.

src/backend/utils/cache/lsyscache.c

+23
Original file line numberDiff line numberDiff line change
@@ -3254,6 +3254,29 @@ get_index_column_opclass(Oid index_oid, int attno)
32543254
return opclass;
32553255
}
32563256

3257+
/*
3258+
* get_index_isreplident
3259+
*
3260+
* Given the index OID, return pg_index.indisreplident.
3261+
*/
3262+
bool
3263+
get_index_isreplident(Oid index_oid)
3264+
{
3265+
HeapTuple tuple;
3266+
Form_pg_index rd_index;
3267+
bool result;
3268+
3269+
tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
3270+
if (!HeapTupleIsValid(tuple))
3271+
return false;
3272+
3273+
rd_index = (Form_pg_index) GETSTRUCT(tuple);
3274+
result = rd_index->indisreplident;
3275+
ReleaseSysCache(tuple);
3276+
3277+
return result;
3278+
}
3279+
32573280
/*
32583281
* get_index_isvalid
32593282
*

src/include/utils/lsyscache.h

+1
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ extern char *get_namespace_name_or_temp(Oid nspid);
182182
extern Oid get_range_subtype(Oid rangeOid);
183183
extern Oid get_range_collation(Oid rangeOid);
184184
extern Oid get_index_column_opclass(Oid index_oid, int attno);
185+
extern bool get_index_isreplident(Oid index_oid);
185186
extern bool get_index_isvalid(Oid index_oid);
186187

187188
#define type_is_array(typid) (get_element_type(typid) != InvalidOid)

src/test/regress/expected/replica_identity.out

+46
Original file line numberDiff line numberDiff line change
@@ -179,5 +179,51 @@ SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass;
179179
n
180180
(1 row)
181181

182+
---
183+
-- Test that ALTER TABLE rewrite preserves nondefault replica identity
184+
---
185+
-- constraint variant
186+
CREATE TABLE test_replica_identity2 (id int UNIQUE NOT NULL);
187+
ALTER TABLE test_replica_identity2 REPLICA IDENTITY USING INDEX test_replica_identity2_id_key;
188+
\d test_replica_identity2
189+
Table "public.test_replica_identity2"
190+
Column | Type | Collation | Nullable | Default
191+
--------+---------+-----------+----------+---------
192+
id | integer | | not null |
193+
Indexes:
194+
"test_replica_identity2_id_key" UNIQUE CONSTRAINT, btree (id) REPLICA IDENTITY
195+
196+
ALTER TABLE test_replica_identity2 ALTER COLUMN id TYPE bigint;
197+
\d test_replica_identity2
198+
Table "public.test_replica_identity2"
199+
Column | Type | Collation | Nullable | Default
200+
--------+--------+-----------+----------+---------
201+
id | bigint | | not null |
202+
Indexes:
203+
"test_replica_identity2_id_key" UNIQUE CONSTRAINT, btree (id) REPLICA IDENTITY
204+
205+
-- straight index variant
206+
CREATE TABLE test_replica_identity3 (id int NOT NULL);
207+
CREATE UNIQUE INDEX test_replica_identity3_id_key ON test_replica_identity3 (id);
208+
ALTER TABLE test_replica_identity3 REPLICA IDENTITY USING INDEX test_replica_identity3_id_key;
209+
\d test_replica_identity3
210+
Table "public.test_replica_identity3"
211+
Column | Type | Collation | Nullable | Default
212+
--------+---------+-----------+----------+---------
213+
id | integer | | not null |
214+
Indexes:
215+
"test_replica_identity3_id_key" UNIQUE, btree (id) REPLICA IDENTITY
216+
217+
ALTER TABLE test_replica_identity3 ALTER COLUMN id TYPE bigint;
218+
\d test_replica_identity3
219+
Table "public.test_replica_identity3"
220+
Column | Type | Collation | Nullable | Default
221+
--------+--------+-----------+----------+---------
222+
id | bigint | | not null |
223+
Indexes:
224+
"test_replica_identity3_id_key" UNIQUE, btree (id) REPLICA IDENTITY
225+
182226
DROP TABLE test_replica_identity;
227+
DROP TABLE test_replica_identity2;
228+
DROP TABLE test_replica_identity3;
183229
DROP TABLE test_replica_identity_othertable;

src/test/regress/sql/replica_identity.sql

+21
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,26 @@ SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass;
7575
ALTER TABLE test_replica_identity REPLICA IDENTITY NOTHING;
7676
SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass;
7777

78+
---
79+
-- Test that ALTER TABLE rewrite preserves nondefault replica identity
80+
---
81+
82+
-- constraint variant
83+
CREATE TABLE test_replica_identity2 (id int UNIQUE NOT NULL);
84+
ALTER TABLE test_replica_identity2 REPLICA IDENTITY USING INDEX test_replica_identity2_id_key;
85+
\d test_replica_identity2
86+
ALTER TABLE test_replica_identity2 ALTER COLUMN id TYPE bigint;
87+
\d test_replica_identity2
88+
89+
-- straight index variant
90+
CREATE TABLE test_replica_identity3 (id int NOT NULL);
91+
CREATE UNIQUE INDEX test_replica_identity3_id_key ON test_replica_identity3 (id);
92+
ALTER TABLE test_replica_identity3 REPLICA IDENTITY USING INDEX test_replica_identity3_id_key;
93+
\d test_replica_identity3
94+
ALTER TABLE test_replica_identity3 ALTER COLUMN id TYPE bigint;
95+
\d test_replica_identity3
96+
7897
DROP TABLE test_replica_identity;
98+
DROP TABLE test_replica_identity2;
99+
DROP TABLE test_replica_identity3;
79100
DROP TABLE test_replica_identity_othertable;

0 commit comments

Comments
 (0)