Invalidate relcache for publications defined for all tables.
authorAmit Kapila <[email protected]>
Wed, 8 Sep 2021 06:20:37 +0000 (11:50 +0530)
committerAmit Kapila <[email protected]>
Wed, 8 Sep 2021 06:20:37 +0000 (11:50 +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/catalog/dependency.c
src/backend/commands/publicationcmds.c
src/include/commands/publicationcmds.h
src/test/regress/expected/publication.out
src/test/regress/sql/publication.sql

index 76b65e39c44303bd7f8d31f5868f3e3835cf34ee..91c3e976e017319912ddf5f554c98e2a1509e436 100644 (file)
@@ -1460,6 +1460,10 @@ doDeletion(const ObjectAddress *object, int flags)
                        RemovePublicationRelById(object->objectId);
                        break;
 
+               case OCLASS_PUBLICATION:
+                       RemovePublicationById(object->objectId);
+                       break;
+
                case OCLASS_CAST:
                case OCLASS_COLLATION:
                case OCLASS_CONVERSION:
@@ -1478,7 +1482,6 @@ doDeletion(const ObjectAddress *object, int flags)
                case OCLASS_USER_MAPPING:
                case OCLASS_DEFACL:
                case OCLASS_EVENT_TRIGGER:
-               case OCLASS_PUBLICATION:
                case OCLASS_TRANSFORM:
                        DropObjectById(object);
                        break;
index 179a0ef9822847142b0d36c34dd14a870de56bf0..30929da1f57305c112f1123168cab2094037c229 100644 (file)
@@ -234,6 +234,11 @@ CreatePublication(ParseState *pstate, 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);
 
@@ -504,6 +509,35 @@ RemovePublicationRelById(Oid proid)
        table_close(rel, RowExclusiveLock);
 }
 
+/*
+ * Remove the publication by mapping OID.
+ */
+void
+RemovePublicationById(Oid pubid)
+{
+       Relation        rel;
+       HeapTuple       tup;
+       Form_pg_publication pubform;
+
+       rel = table_open(PublicationRelationId, RowExclusiveLock);
+
+       tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(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);
+
+       table_close(rel, RowExclusiveLock);
+}
+
 /*
  * Open relations specified by a PublicationTable list.
  * In the returned list of PublicationRelInfo, tables are locked
index a3fa2ac6cdc83ae8ea4d88769d0e6600f20f6994..c98d519b29d02bba5366053e48b5abcf7a263f9d 100644 (file)
@@ -20,6 +20,7 @@
 
 extern ObjectAddress CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt);
 extern void AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt);
+extern void RemovePublicationById(Oid pubid);
 extern void RemovePublicationRelById(Oid proid);
 
 extern ObjectAddress AlterPublicationOwner(const char *name, Oid newOwnerId);
index 4a5ef0bc24928a02a13ad81e4c30df92b3ffbc83..cad1b374be25b3d2e909bc834d3ea2a2ed2dee43 100644 (file)
@@ -158,6 +158,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:  cannot add relation "testpub_view" to publication
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';