Invalidate relcache for publications defined for all tables.
authorAmit Kapila
Wed, 8 Sep 2021 04:50:02 +0000 (10:20 +0530)
committerAmit Kapila
Wed, 8 Sep 2021 06:44:59 +0000 (12:14 +0530)
Updates/Deletes on a relation were allowed even without replica identity
after we define the publication for all tables. This would later lead to
an error on subscribers. The reason was that for such publications we were
not invalidating the relcache and the publication information for
relations was not getting rebuilt. Similarly, we were not invalidating the
relcache after dropping of such publications which will prohibit
Updates/Deletes without replica identity even without any publication.

Author: Vignesh C and Hou Zhijie
Reviewed-by: Hou Zhijie, Kyotaro Horiguchi, Amit Kapila
Backpatch-through: 10, where it was introduced
Discussion: https://postgr.es/m/CALDaNm0pF6zeWqCA8TCe2sDuwFAy8fCqba=nHampCKag-qLixg@mail.gmail.com

src/backend/commands/publicationcmds.c
src/test/regress/expected/publication.out
src/test/regress/sql/publication.sql

index a5e29b5a8274217c613f6314bd3c0ba0ef619a7d..879710143e155c0da36ec488967b6db29a846234 100644 (file)
@@ -236,6 +236,11 @@ CreatePublication(CreatePublicationStmt *stmt)
        PublicationAddTables(puboid, rels, true, NULL);
        CloseTableList(rels);
    }
+   else if (stmt->for_all_tables)
+   {
+       /* Invalidate relcache so that publication info is rebuilt. */
+       CacheInvalidateRelcacheAll();
+   }
 
    table_close(rel, RowExclusiveLock);
 
@@ -469,13 +474,14 @@ AlterPublication(AlterPublicationStmt *stmt)
 }
 
 /*
- * Drop publication by OID
+ * Remove the publication by mapping OID.
  */
 void
 RemovePublicationById(Oid pubid)
 {
    Relation    rel;
    HeapTuple   tup;
+   Form_pg_publication pubform;
 
    rel = table_open(PublicationRelationId, RowExclusiveLock);
 
@@ -484,6 +490,12 @@ RemovePublicationById(Oid pubid)
    if (!HeapTupleIsValid(tup))
        elog(ERROR, "cache lookup failed for publication %u", pubid);
 
+   pubform = (Form_pg_publication) GETSTRUCT(tup);
+
+   /* Invalidate relcache so that publication info is rebuilt. */
+   if (pubform->puballtables)
+       CacheInvalidateRelcacheAll();
+
    CatalogTupleDelete(rel, &tup->t_self);
 
    ReleaseSysCache(tup);
index 63d6ab7a4ef265b3a5286453d85f05502e274e91..c299702480270e6a6a0e0586e9c49a78e2003378 100644 (file)
@@ -156,6 +156,21 @@ Tables:
 
 DROP TABLE testpub_parted1;
 DROP PUBLICATION testpub_forparted, testpub_forparted1;
+-- Test cache invalidation FOR ALL TABLES publication
+SET client_min_messages = 'ERROR';
+CREATE TABLE testpub_tbl4(a int);
+INSERT INTO testpub_tbl4 values(1);
+UPDATE testpub_tbl4 set a = 2;
+CREATE PUBLICATION testpub_foralltables FOR ALL TABLES;
+RESET client_min_messages;
+-- fail missing REPLICA IDENTITY
+UPDATE testpub_tbl4 set a = 3;
+ERROR:  cannot update table "testpub_tbl4" because it does not have a replica identity and publishes updates
+HINT:  To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.
+DROP PUBLICATION testpub_foralltables;
+-- should pass after dropping the publication
+UPDATE testpub_tbl4 set a = 3;
+DROP TABLE testpub_tbl4;
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 ERROR:  "testpub_view" is not a table
index d844075368d0c56c051beb5effab21383d3a8682..04b34ee2998c5a65b50c9a56151cc13238bd998f 100644 (file)
@@ -93,6 +93,20 @@ ALTER PUBLICATION testpub_forparted SET (publish_via_partition_root = true);
 DROP TABLE testpub_parted1;
 DROP PUBLICATION testpub_forparted, testpub_forparted1;
 
+-- Test cache invalidation FOR ALL TABLES publication
+SET client_min_messages = 'ERROR';
+CREATE TABLE testpub_tbl4(a int);
+INSERT INTO testpub_tbl4 values(1);
+UPDATE testpub_tbl4 set a = 2;
+CREATE PUBLICATION testpub_foralltables FOR ALL TABLES;
+RESET client_min_messages;
+-- fail missing REPLICA IDENTITY
+UPDATE testpub_tbl4 set a = 3;
+DROP PUBLICATION testpub_foralltables;
+-- should pass after dropping the publication
+UPDATE testpub_tbl4 set a = 3;
+DROP TABLE testpub_tbl4;
+
 -- fail - view
 CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_view;
 SET client_min_messages = 'ERROR';