aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2022-01-22 13:32:40 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2022-01-22 13:32:40 -0500
commit3839e29c58b44639bb6800f3415af87f4d1fb655 (patch)
tree63fe9eb26c4bdb6b5e84e20b509fd094b98ec8c5 /src
parentf4ebf0dbea835da85c21988321258a587a567dbd (diff)
downloadpostgresql-3839e29c58b44639bb6800f3415af87f4d1fb655.tar.gz
postgresql-3839e29c58b44639bb6800f3415af87f4d1fb655.zip
Flush table's relcache during ALTER TABLE ADD PRIMARY KEY USING INDEX.
Previously, unless we had to add a NOT NULL constraint to the column, this command resulted in updating only the index's relcache entry. That's problematic when replication behavior is being driven off the existence of a primary key: other sessions (and ours too for that matter) failed to recalculate their opinion of whether the table can be replicated. Add a relcache invalidation to fix it. This has been broken since pg_class.relhaspkey was removed in v11. Before that, updating the table's relhaspkey value sufficed to cause a cache flush. Hence, backpatch to v11. Report and patch by Hou Zhijie Discussion: https://postgr.es/m/OS0PR01MB5716EBE01F112C62F8F9B786947B9@OS0PR01MB5716.jpnprd01.prod.outlook.com
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/index.c11
-rw-r--r--src/test/regress/expected/publication.out14
-rw-r--r--src/test/regress/sql/publication.sql13
3 files changed, 38 insertions, 0 deletions
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index d232a213088..0ee09987812 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -2050,6 +2050,7 @@ index_constraint_create(Relation heapRelation,
HeapTuple indexTuple;
Form_pg_index indexForm;
bool dirty = false;
+ bool marked_as_primary = false;
pg_index = table_open(IndexRelationId, RowExclusiveLock);
@@ -2063,6 +2064,7 @@ index_constraint_create(Relation heapRelation,
{
indexForm->indisprimary = true;
dirty = true;
+ marked_as_primary = true;
}
if (deferrable && indexForm->indimmediate)
@@ -2075,6 +2077,15 @@ index_constraint_create(Relation heapRelation,
{
CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple);
+ /*
+ * When we mark an existing index as primary, force a relcache
+ * flush on its parent table, so that all sessions will become
+ * aware that the table now has a primary key. This is important
+ * because it affects some replication behaviors.
+ */
+ if (marked_as_primary)
+ CacheInvalidateRelcache(heapRelation);
+
InvokeObjectPostAlterHookArg(IndexRelationId, indexRelationId, 0,
InvalidOid, is_internal);
}
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index a2aca234ef8..7c7e0226658 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -268,6 +268,20 @@ Publications:
"testpib_ins_trunct"
"testpub_fortbl"
+-- verify relation cache invalidation when a primary key is added using
+-- an existing index
+CREATE TABLE pub_test.testpub_addpk (id int not null, data int);
+ALTER PUBLICATION testpub_default ADD TABLE pub_test.testpub_addpk;
+INSERT INTO pub_test.testpub_addpk VALUES(1, 11);
+CREATE UNIQUE INDEX testpub_addpk_id_idx ON pub_test.testpub_addpk(id);
+-- fail:
+UPDATE pub_test.testpub_addpk SET id = 2;
+ERROR: cannot update table "testpub_addpk" because it does not have a replica identity and publishes updates
+HINT: To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.
+ALTER TABLE pub_test.testpub_addpk ADD PRIMARY KEY USING INDEX testpub_addpk_id_idx;
+-- now it should work:
+UPDATE pub_test.testpub_addpk SET id = 2;
+DROP TABLE pub_test.testpub_addpk;
-- permissions
SET ROLE regress_publication_user2;
CREATE PUBLICATION testpub2; -- fail
diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql
index 4f2445ad117..4b7738395ec 100644
--- a/src/test/regress/sql/publication.sql
+++ b/src/test/regress/sql/publication.sql
@@ -149,6 +149,19 @@ ALTER PUBLICATION testpub_default DROP TABLE pub_test.testpub_nopk;
\d+ testpub_tbl1
+-- verify relation cache invalidation when a primary key is added using
+-- an existing index
+CREATE TABLE pub_test.testpub_addpk (id int not null, data int);
+ALTER PUBLICATION testpub_default ADD TABLE pub_test.testpub_addpk;
+INSERT INTO pub_test.testpub_addpk VALUES(1, 11);
+CREATE UNIQUE INDEX testpub_addpk_id_idx ON pub_test.testpub_addpk(id);
+-- fail:
+UPDATE pub_test.testpub_addpk SET id = 2;
+ALTER TABLE pub_test.testpub_addpk ADD PRIMARY KEY USING INDEX testpub_addpk_id_idx;
+-- now it should work:
+UPDATE pub_test.testpub_addpk SET id = 2;
+DROP TABLE pub_test.testpub_addpk;
+
-- permissions
SET ROLE regress_publication_user2;
CREATE PUBLICATION testpub2; -- fail