@@ -354,7 +354,8 @@ GetPubPartitionOptionRelations(List *result, PublicationPartOpt pub_partopt,
354354 * ancestor is at the end of the list.
355355 */
356356Oid
357- GetTopMostAncestorInPublication (Oid puboid , List * ancestors , int * ancestor_level )
357+ GetTopMostAncestorInPublication (Oid puboid , List * ancestors ,
358+ int * ancestor_level , bool puballtables )
358359{
359360 ListCell * lc ;
360361 Oid topmost_relid = InvalidOid ;
@@ -366,32 +367,43 @@ GetTopMostAncestorInPublication(Oid puboid, List *ancestors, int *ancestor_level
366367 foreach (lc , ancestors )
367368 {
368369 Oid ancestor = lfirst_oid (lc );
369- List * apubids = GetRelationPublications (ancestor );
370- List * aschemaPubids = NIL ;
370+ List * apubids = NIL ;
371+ List * aexceptpubids = NIL ;
372+ List * aschemapubids = NIL ;
373+ bool set_top = false;
374+
375+ GetRelationPublications (ancestor , & apubids , & aexceptpubids );
371376
372377 level ++ ;
373378
374- if (list_member_oid (apubids , puboid ))
379+ /* check if member of table publications */
380+ set_top = list_member_oid (apubids , puboid );
381+ if (!set_top )
375382 {
376- topmost_relid = ancestor ;
383+ aschemapubids = GetSchemaPublications ( get_rel_namespace ( ancestor )) ;
377384
378- if (ancestor_level )
379- * ancestor_level = level ;
385+ /* check if member of schema publications */
386+ set_top = list_member_oid (aschemapubids , puboid );
387+
388+ /*
389+ * If the publication is all tables publication and the table is
390+ * not part of exception tables.
391+ */
392+ if (!set_top && puballtables )
393+ set_top = !list_member_oid (aexceptpubids , puboid );
380394 }
381- else
395+
396+ if (set_top )
382397 {
383- aschemaPubids = GetSchemaPublications (get_rel_namespace (ancestor ));
384- if (list_member_oid (aschemaPubids , puboid ))
385- {
386- topmost_relid = ancestor ;
398+ topmost_relid = ancestor ;
387399
388- if (ancestor_level )
389- * ancestor_level = level ;
390- }
400+ if (ancestor_level )
401+ * ancestor_level = level ;
391402 }
392403
393404 list_free (apubids );
394- list_free (aschemaPubids );
405+ list_free (aschemapubids );
406+ list_free (aexceptpubids );
395407 }
396408
397409 return topmost_relid ;
@@ -466,6 +478,26 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri,
466478 RelationGetRelationName (targetrel ), pub -> name )));
467479 }
468480
481+ /*
482+ * Check when a partition is excluded via EXCEPT TABLE while the
483+ * publication has publish_via_partition_root = true.
484+ */
485+ if (pub -> alltables && pub -> pubviaroot && pri -> except &&
486+ targetrel -> rd_rel -> relispartition )
487+ ereport (WARNING ,
488+ (errmsg ("partition \"%s\" might be replicated as publish_via_partition_root is \"%s\"" ,
489+ RelationGetRelationName (targetrel ), "true" )));
490+
491+ /*
492+ * Check when a partitioned table is excluded via EXCEPT TABLE while the
493+ * publication has publish_via_partition_root = false.
494+ */
495+ if (pub -> alltables && !pub -> pubviaroot && pri -> except &&
496+ targetrel -> rd_rel -> relkind == RELKIND_PARTITIONED_TABLE )
497+ ereport (WARNING ,
498+ (errmsg ("partitioned table \"%s\" might be replicated as publish_via_partition_root is \"%s\"" ,
499+ RelationGetRelationName (targetrel ), "false" )));
500+
469501 check_publication_add_relation (targetrel );
470502
471503 /* Validate and translate column names into a Bitmapset of attnums. */
@@ -482,6 +514,8 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri,
482514 ObjectIdGetDatum (pubid );
483515 values [Anum_pg_publication_rel_prrelid - 1 ] =
484516 ObjectIdGetDatum (relid );
517+ values [Anum_pg_publication_rel_prexcept - 1 ] =
518+ BoolGetDatum (pri -> except );
485519
486520 /* Add qualifications, if available */
487521 if (pri -> whereClause != NULL )
@@ -749,35 +783,59 @@ publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists)
749783 return myself ;
750784}
751785
752- /* Gets list of publication oids for a relation */
753- List *
754- GetRelationPublications (Oid relid )
786+ /*
787+ * Get the list of publication oids associated with a specified relation.
788+ * pubids is filled with the list of publication oids the relation is part of.
789+ * except_pubids is filled with the list of publication oids the relation is
790+ * excluded from.
791+ *
792+ * This function returns true if the relation is part of any publication.
793+ */
794+ bool
795+ GetRelationPublications (Oid relid , List * * pubids , List * * except_pubids )
755796{
756- List * result = NIL ;
757797 CatCList * pubrellist ;
758- int i ;
798+ bool found = false ;
759799
760800 /* Find all publications associated with the relation. */
761801 pubrellist = SearchSysCacheList1 (PUBLICATIONRELMAP ,
762802 ObjectIdGetDatum (relid ));
763- for (i = 0 ; i < pubrellist -> n_members ; i ++ )
803+ for (int i = 0 ; i < pubrellist -> n_members ; i ++ )
764804 {
765805 HeapTuple tup = & pubrellist -> members [i ]-> tuple ;
766- Oid pubid = ((Form_pg_publication_rel ) GETSTRUCT (tup ))-> prpubid ;
806+ Form_pg_publication_rel pubrel = (Form_pg_publication_rel ) GETSTRUCT (tup );
807+ Oid pubid = pubrel -> prpubid ;
767808
768- result = lappend_oid (result , pubid );
809+ if (pubrel -> prexcept )
810+ {
811+ if (except_pubids )
812+ * except_pubids = lappend_oid (* except_pubids , pubid );
813+ }
814+ else
815+ {
816+ if (pubids )
817+ * pubids = lappend_oid (* pubids , pubid );
818+ found = true;
819+ }
769820 }
770821
771822 ReleaseSysCacheList (pubrellist );
772823
773- return result ;
824+ return found ;
774825}
775826
776827/*
777- * Gets list of relation oids for a publication.
828+ * Return the list of relation OIDs for a publication.
829+ *
830+ * For a FOR ALL TABLES publication, this returns the list of tables that were
831+ * explicitly excluded via an EXCEPT TABLE clause.
832+ *
833+ * For a FOR TABLE publication, this returns the list of tables explicitly
834+ * included in the publication.
778835 *
779- * This should only be used FOR TABLE publications, the FOR ALL TABLES/SEQUENCES
780- * should use GetAllPublicationRelations().
836+ * Publications declared with FOR ALL TABLES or FOR ALL SEQUENCES should use
837+ * GetAllPublicationRelations() to obtain the complete set of tables covered by
838+ * the publication.
781839 */
782840List *
783841GetPublicationRelations (Oid pubid , PublicationPartOpt pub_partopt )
@@ -864,15 +922,23 @@ GetAllTablesPublications(void)
864922 * partitioned tables, we must exclude partitions in favor of including the
865923 * root partitioned tables. This is not applicable to FOR ALL SEQUENCES
866924 * publication.
925+ *
926+ * The list does not include relations that are explicitly excluded via the
927+ * EXCEPT TABLE clause of the publication specified by pubid.
867928 */
868929List *
869- GetAllPublicationRelations (char relkind , bool pubviaroot )
930+ GetAllPublicationRelations (Oid pubid , char relkind , bool pubviaroot )
870931{
871932 Relation classRel ;
872933 ScanKeyData key [1 ];
873934 TableScanDesc scan ;
874935 HeapTuple tuple ;
875936 List * result = NIL ;
937+ List * exceptlist ;
938+
939+ exceptlist = GetPublicationRelations (pubid , pubviaroot ?
940+ PUBLICATION_PART_ALL :
941+ PUBLICATION_PART_ROOT );
876942
877943 Assert (!(relkind == RELKIND_SEQUENCE && pubviaroot ));
878944
@@ -891,7 +957,8 @@ GetAllPublicationRelations(char relkind, bool pubviaroot)
891957 Oid relid = relForm -> oid ;
892958
893959 if (is_publishable_class (relid , relForm ) &&
894- !(relForm -> relispartition && pubviaroot ))
960+ !(relForm -> relispartition && pubviaroot ) &&
961+ !list_member_oid (exceptlist , relid ))
895962 result = lappend_oid (result , relid );
896963 }
897964
@@ -912,7 +979,8 @@ GetAllPublicationRelations(char relkind, bool pubviaroot)
912979 Oid relid = relForm -> oid ;
913980
914981 if (is_publishable_class (relid , relForm ) &&
915- !relForm -> relispartition )
982+ !relForm -> relispartition &&
983+ !list_member_oid (exceptlist , relid ))
916984 result = lappend_oid (result , relid );
917985 }
918986
@@ -1168,7 +1236,8 @@ pg_get_publication_tables(PG_FUNCTION_ARGS)
11681236 * those. Otherwise, get the partitioned table itself.
11691237 */
11701238 if (pub_elem -> alltables )
1171- pub_elem_tables = GetAllPublicationRelations (RELKIND_RELATION ,
1239+ pub_elem_tables = GetAllPublicationRelations (pub_elem -> oid ,
1240+ RELKIND_RELATION ,
11721241 pub_elem -> pubviaroot );
11731242 else
11741243 {
@@ -1367,7 +1436,7 @@ pg_get_publication_sequences(PG_FUNCTION_ARGS)
13671436 publication = GetPublicationByName (pubname , false);
13681437
13691438 if (publication -> allsequences )
1370- sequences = GetAllPublicationRelations (RELKIND_SEQUENCE , false);
1439+ sequences = GetAllPublicationRelations (publication -> oid , RELKIND_SEQUENCE , false);
13711440
13721441 funcctx -> user_fctx = sequences ;
13731442
0 commit comments