2424#include "catalog/index.h"
2525#include "catalog/indexing.h"
2626#include "catalog/namespace.h"
27+ #include "catalog/partition.h"
2728#include "catalog/objectaccess.h"
2829#include "catalog/objectaddress.h"
30+ #include "catalog/pg_inherits.h"
2931#include "catalog/pg_publication.h"
3032#include "catalog/pg_publication_rel.h"
3133#include "catalog/pg_type.h"
4042#include "utils/rel.h"
4143#include "utils/syscache.h"
4244
45+ static List * get_rel_publications (Oid relid );
46+
4347/*
4448 * Check if relation can be in given publication and throws appropriate
4549 * error if not.
4650 */
4751static void
4852check_publication_add_relation (Relation targetrel )
4953{
50- /* Give more specific error for partitioned tables */
51- if (RelationGetForm (targetrel )-> relkind == RELKIND_PARTITIONED_TABLE )
52- ereport (ERROR ,
53- (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
54- errmsg ("\"%s\" is a partitioned table" ,
55- RelationGetRelationName (targetrel )),
56- errdetail ("Adding partitioned tables to publications is not supported." ),
57- errhint ("You can add the table partitions individually." )));
58-
59- /* Must be table */
60- if (RelationGetForm (targetrel )-> relkind != RELKIND_RELATION )
54+ /* Must be a regular or partitioned table */
55+ if (RelationGetForm (targetrel )-> relkind != RELKIND_RELATION &&
56+ RelationGetForm (targetrel )-> relkind != RELKIND_PARTITIONED_TABLE )
6157 ereport (ERROR ,
6258 (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6359 errmsg ("\"%s\" is not a table" ,
@@ -103,7 +99,8 @@ check_publication_add_relation(Relation targetrel)
10399static bool
104100is_publishable_class (Oid relid , Form_pg_class reltuple )
105101{
106- return reltuple -> relkind == RELKIND_RELATION &&
102+ return (reltuple -> relkind == RELKIND_RELATION ||
103+ reltuple -> relkind == RELKIND_PARTITIONED_TABLE ) &&
107104 !IsCatalogRelationOid (relid ) &&
108105 reltuple -> relpersistence == RELPERSISTENCE_PERMANENT &&
109106 relid >= FirstNormalObjectId ;
@@ -221,10 +218,35 @@ publication_add_relation(Oid pubid, Relation targetrel,
221218
222219
223220/*
224- * Gets list of publication oids for a relation oid.
221+ * Gets list of publication oids for a relation, plus those of ancestors,
222+ * if any, if the relation is a partition.
225223 */
226224List *
227225GetRelationPublications (Oid relid )
226+ {
227+ List * result = NIL ;
228+
229+ result = get_rel_publications (relid );
230+ if (get_rel_relispartition (relid ))
231+ {
232+ List * ancestors = get_partition_ancestors (relid );
233+ ListCell * lc ;
234+
235+ foreach (lc , ancestors )
236+ {
237+ Oid ancestor = lfirst_oid (lc );
238+ List * ancestor_pubs = get_rel_publications (ancestor );
239+
240+ result = list_concat (result , ancestor_pubs );
241+ }
242+ }
243+
244+ return result ;
245+ }
246+
247+ /* Workhorse of GetRelationPublications() */
248+ static List *
249+ get_rel_publications (Oid relid )
228250{
229251 List * result = NIL ;
230252 CatCList * pubrellist ;
@@ -253,7 +275,7 @@ GetRelationPublications(Oid relid)
253275 * should use GetAllTablesPublicationRelations().
254276 */
255277List *
256- GetPublicationRelations (Oid pubid )
278+ GetPublicationRelations (Oid pubid , PublicationPartOpt pub_partopt )
257279{
258280 List * result ;
259281 Relation pubrelsrel ;
@@ -279,7 +301,31 @@ GetPublicationRelations(Oid pubid)
279301
280302 pubrel = (Form_pg_publication_rel ) GETSTRUCT (tup );
281303
282- result = lappend_oid (result , pubrel -> prrelid );
304+ if (get_rel_relkind (pubrel -> prrelid ) == RELKIND_PARTITIONED_TABLE &&
305+ pub_partopt != PUBLICATION_PART_ROOT )
306+ {
307+ List * all_parts = find_all_inheritors (pubrel -> prrelid , NoLock ,
308+ NULL );
309+
310+ if (pub_partopt == PUBLICATION_PART_ALL )
311+ result = list_concat (result , all_parts );
312+ else if (pub_partopt == PUBLICATION_PART_LEAF )
313+ {
314+ ListCell * lc ;
315+
316+ foreach (lc , all_parts )
317+ {
318+ Oid partOid = lfirst_oid (lc );
319+
320+ if (get_rel_relkind (partOid ) != RELKIND_PARTITIONED_TABLE )
321+ result = lappend_oid (result , partOid );
322+ }
323+ }
324+ else
325+ Assert (false);
326+ }
327+ else
328+ result = lappend_oid (result , pubrel -> prrelid );
283329 }
284330
285331 systable_endscan (scan );
@@ -480,10 +526,17 @@ pg_get_publication_tables(PG_FUNCTION_ARGS)
480526 oldcontext = MemoryContextSwitchTo (funcctx -> multi_call_memory_ctx );
481527
482528 publication = GetPublicationByName (pubname , false);
529+
530+ /*
531+ * Publications support partitioned tables, although all changes are
532+ * replicated using leaf partition identity and schema, so we only
533+ * need those.
534+ */
483535 if (publication -> alltables )
484536 tables = GetAllTablesPublicationRelations ();
485537 else
486- tables = GetPublicationRelations (publication -> oid );
538+ tables = GetPublicationRelations (publication -> oid ,
539+ PUBLICATION_PART_LEAF );
487540 funcctx -> user_fctx = (void * ) tables ;
488541
489542 MemoryContextSwitchTo (oldcontext );
0 commit comments