PostgreSQL Source Code  git master
pg_publication.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/tableam.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaddress.h"
#include "catalog/partition.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_publication.h"
#include "catalog/pg_publication_namespace.h"
#include "catalog/pg_publication_rel.h"
#include "catalog/pg_type.h"
#include "commands/publicationcmds.h"
#include "funcapi.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for pg_publication.c:

Go to the source code of this file.

Data Structures

struct  published_rel
 

Macros

#define NUM_PUBLICATION_TABLES_ELEM   4
 

Functions

static void check_publication_add_relation (Relation targetrel)
 
static void check_publication_add_schema (Oid schemaid)
 
static bool is_publishable_class (Oid relid, Form_pg_class reltuple)
 
bool is_publishable_relation (Relation rel)
 
Datum pg_relation_is_publishable (PG_FUNCTION_ARGS)
 
static bool is_ancestor_member_tableinfos (Oid ancestor, List *table_infos)
 
static void filter_partitions (List *table_infos)
 
bool is_schema_publication (Oid pubid)
 
ListGetPubPartitionOptionRelations (List *result, PublicationPartOpt pub_partopt, Oid relid)
 
Oid GetTopMostAncestorInPublication (Oid puboid, List *ancestors, int *ancestor_level)
 
static int2vectorattnumstoint2vector (Bitmapset *attrs)
 
ObjectAddress publication_add_relation (Oid pubid, PublicationRelInfo *pri, bool if_not_exists)
 
Bitmapsetpub_collist_validate (Relation targetrel, List *columns)
 
Bitmapsetpub_collist_to_bitmapset (Bitmapset *columns, Datum pubcols, MemoryContext mcxt)
 
ObjectAddress publication_add_schema (Oid pubid, Oid schemaid, bool if_not_exists)
 
ListGetRelationPublications (Oid relid)
 
ListGetPublicationRelations (Oid pubid, PublicationPartOpt pub_partopt)
 
ListGetAllTablesPublications (void)
 
ListGetAllTablesPublicationRelations (bool pubviaroot)
 
ListGetPublicationSchemas (Oid pubid)
 
ListGetSchemaPublications (Oid schemaid)
 
ListGetSchemaPublicationRelations (Oid schemaid, PublicationPartOpt pub_partopt)
 
ListGetAllSchemaPublicationRelations (Oid pubid, PublicationPartOpt pub_partopt)
 
PublicationGetPublication (Oid pubid)
 
PublicationGetPublicationByName (const char *pubname, bool missing_ok)
 
Datum pg_get_publication_tables (PG_FUNCTION_ARGS)
 

Macro Definition Documentation

◆ NUM_PUBLICATION_TABLES_ELEM

#define NUM_PUBLICATION_TABLES_ELEM   4

Function Documentation

◆ attnumstoint2vector()

static int2vector* attnumstoint2vector ( Bitmapset attrs)
static

Definition at line 359 of file pg_publication.c.

360 {
361  int2vector *result;
362  int n = bms_num_members(attrs);
363  int i = -1;
364  int j = 0;
365 
366  result = buildint2vector(NULL, n);
367 
368  while ((i = bms_next_member(attrs, i)) >= 0)
369  {
370  Assert(i <= PG_INT16_MAX);
371 
372  result->values[j++] = (int16) i;
373  }
374 
375  return result;
376 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:751
signed short int16
Definition: c.h:493
#define Assert(condition)
Definition: c.h:858
#define PG_INT16_MAX
Definition: c.h:586
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:114
int j
Definition: isn.c:74
int i
Definition: isn.c:73
Definition: c.h:715
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:722

References Assert, bms_next_member(), bms_num_members(), buildint2vector(), i, j, PG_INT16_MAX, and int2vector::values.

Referenced by publication_add_relation().

◆ check_publication_add_relation()

static void check_publication_add_relation ( Relation  targetrel)
static

Definition at line 56 of file pg_publication.c.

57 {
58  /* Must be a regular or partitioned table */
59  if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
60  RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
61  ereport(ERROR,
62  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
63  errmsg("cannot add relation \"%s\" to publication",
64  RelationGetRelationName(targetrel)),
65  errdetail_relkind_not_supported(RelationGetForm(targetrel)->relkind)));
66 
67  /* Can't be system table */
68  if (IsCatalogRelation(targetrel))
69  ereport(ERROR,
70  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
71  errmsg("cannot add relation \"%s\" to publication",
72  RelationGetRelationName(targetrel)),
73  errdetail("This operation is not supported for system tables.")));
74 
75  /* UNLOGGED and TEMP relations cannot be part of publication. */
76  if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
77  ereport(ERROR,
78  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
79  errmsg("cannot add relation \"%s\" to publication",
80  RelationGetRelationName(targetrel)),
81  errdetail("This operation is not supported for temporary tables.")));
82  else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
83  ereport(ERROR,
84  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
85  errmsg("cannot add relation \"%s\" to publication",
86  RelationGetRelationName(targetrel)),
87  errdetail("This operation is not supported for unlogged tables.")));
88 }
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:103
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
#define RelationGetForm(relation)
Definition: rel.h:499
#define RelationGetRelationName(relation)
Definition: rel.h:539
Form_pg_class rd_rel
Definition: rel.h:111

References ereport, errcode(), errdetail(), errdetail_relkind_not_supported(), errmsg(), ERROR, IsCatalogRelation(), RelationData::rd_rel, RelationGetForm, and RelationGetRelationName.

Referenced by publication_add_relation().

◆ check_publication_add_schema()

static void check_publication_add_schema ( Oid  schemaid)
static

Definition at line 95 of file pg_publication.c.

96 {
97  /* Can't be system namespace */
98  if (IsCatalogNamespace(schemaid) || IsToastNamespace(schemaid))
99  ereport(ERROR,
100  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
101  errmsg("cannot add schema \"%s\" to publication",
102  get_namespace_name(schemaid)),
103  errdetail("This operation is not supported for system schemas.")));
104 
105  /* Can't be temporary namespace */
106  if (isAnyTempNamespace(schemaid))
107  ereport(ERROR,
108  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
109  errmsg("cannot add schema \"%s\" to publication",
110  get_namespace_name(schemaid)),
111  errdetail("Temporary schemas cannot be replicated.")));
112 }
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:221
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:203
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3672

References ereport, errcode(), errdetail(), errmsg(), ERROR, get_namespace_name(), isAnyTempNamespace(), IsCatalogNamespace(), and IsToastNamespace().

Referenced by publication_add_schema().

◆ filter_partitions()

static void filter_partitions ( List table_infos)
static

Definition at line 198 of file pg_publication.c.

199 {
200  ListCell *lc;
201 
202  foreach(lc, table_infos)
203  {
204  bool skip = false;
205  List *ancestors = NIL;
206  ListCell *lc2;
207  published_rel *table_info = (published_rel *) lfirst(lc);
208 
209  if (get_rel_relispartition(table_info->relid))
210  ancestors = get_partition_ancestors(table_info->relid);
211 
212  foreach(lc2, ancestors)
213  {
214  Oid ancestor = lfirst_oid(lc2);
215 
216  if (is_ancestor_member_tableinfos(ancestor, table_infos))
217  {
218  skip = true;
219  break;
220  }
221  }
222 
223  if (skip)
224  table_infos = foreach_delete_current(table_infos, lc);
225  }
226 }
bool get_rel_relispartition(Oid relid)
Definition: lsyscache.c:2027
List * get_partition_ancestors(Oid relid)
Definition: partition.c:134
static const struct exclude_list_item skip[]
Definition: pg_checksums.c:108
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
#define lfirst_oid(lc)
Definition: pg_list.h:174
static bool is_ancestor_member_tableinfos(Oid ancestor, List *table_infos)
unsigned int Oid
Definition: postgres_ext.h:31
Definition: pg_list.h:54

References foreach_delete_current, get_partition_ancestors(), get_rel_relispartition(), is_ancestor_member_tableinfos(), lfirst, lfirst_oid, NIL, published_rel::relid, and skip.

Referenced by pg_get_publication_tables().

◆ GetAllSchemaPublicationRelations()

List* GetAllSchemaPublicationRelations ( Oid  pubid,
PublicationPartOpt  pub_partopt 
)

Definition at line 964 of file pg_publication.c.

965 {
966  List *result = NIL;
967  List *pubschemalist = GetPublicationSchemas(pubid);
968  ListCell *cell;
969 
970  foreach(cell, pubschemalist)
971  {
972  Oid schemaid = lfirst_oid(cell);
973  List *schemaRels = NIL;
974 
975  schemaRels = GetSchemaPublicationRelations(schemaid, pub_partopt);
976  result = list_concat(result, schemaRels);
977  }
978 
979  return result;
980 }
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
List * GetPublicationSchemas(Oid pubid)
List * GetSchemaPublicationRelations(Oid schemaid, PublicationPartOpt pub_partopt)

References GetPublicationSchemas(), GetSchemaPublicationRelations(), lfirst_oid, list_concat(), and NIL.

Referenced by AlterPublicationOptions(), and pg_get_publication_tables().

◆ GetAllTablesPublicationRelations()

List* GetAllTablesPublicationRelations ( bool  pubviaroot)

Definition at line 782 of file pg_publication.c.

783 {
784  Relation classRel;
785  ScanKeyData key[1];
786  TableScanDesc scan;
787  HeapTuple tuple;
788  List *result = NIL;
789 
790  classRel = table_open(RelationRelationId, AccessShareLock);
791 
792  ScanKeyInit(&key[0],
793  Anum_pg_class_relkind,
794  BTEqualStrategyNumber, F_CHAREQ,
795  CharGetDatum(RELKIND_RELATION));
796 
797  scan = table_beginscan_catalog(classRel, 1, key);
798 
799  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
800  {
801  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
802  Oid relid = relForm->oid;
803 
804  if (is_publishable_class(relid, relForm) &&
805  !(relForm->relispartition && pubviaroot))
806  result = lappend_oid(result, relid);
807  }
808 
809  table_endscan(scan);
810 
811  if (pubviaroot)
812  {
813  ScanKeyInit(&key[0],
814  Anum_pg_class_relkind,
815  BTEqualStrategyNumber, F_CHAREQ,
816  CharGetDatum(RELKIND_PARTITIONED_TABLE));
817 
818  scan = table_beginscan_catalog(classRel, 1, key);
819 
820  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
821  {
822  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
823  Oid relid = relForm->oid;
824 
825  if (is_publishable_class(relid, relForm) &&
826  !relForm->relispartition)
827  result = lappend_oid(result, relid);
828  }
829 
830  table_endscan(scan);
831  }
832 
833  table_close(classRel, AccessShareLock);
834  return result;
835 }
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1234
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
#define AccessShareLock
Definition: lockdefs.h:36
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
static bool is_publishable_class(Oid relid, Form_pg_class reltuple)
static Datum CharGetDatum(char X)
Definition: postgres.h:122
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
@ ForwardScanDirection
Definition: sdir.h:28
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:1019

References AccessShareLock, BTEqualStrategyNumber, CharGetDatum(), ForwardScanDirection, GETSTRUCT, heap_getnext(), is_publishable_class(), sort-test::key, lappend_oid(), NIL, ScanKeyInit(), table_beginscan_catalog(), table_close(), table_endscan(), and table_open().

Referenced by pg_get_publication_tables().

◆ GetAllTablesPublications()

List* GetAllTablesPublications ( void  )

Definition at line 741 of file pg_publication.c.

742 {
743  List *result;
744  Relation rel;
745  ScanKeyData scankey;
746  SysScanDesc scan;
747  HeapTuple tup;
748 
749  /* Find all publications that are marked as for all tables. */
750  rel = table_open(PublicationRelationId, AccessShareLock);
751 
752  ScanKeyInit(&scankey,
753  Anum_pg_publication_puballtables,
754  BTEqualStrategyNumber, F_BOOLEQ,
755  BoolGetDatum(true));
756 
757  scan = systable_beginscan(rel, InvalidOid, false,
758  NULL, 1, &scankey);
759 
760  result = NIL;
761  while (HeapTupleIsValid(tup = systable_getnext(scan)))
762  {
763  Oid oid = ((Form_pg_publication) GETSTRUCT(tup))->oid;
764 
765  result = lappend_oid(result, oid);
766  }
767 
768  systable_endscan(scan);
770 
771  return result;
772 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:602
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:509
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:385
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_publication * Form_pg_publication
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
#define InvalidOid
Definition: postgres_ext.h:36

References AccessShareLock, BoolGetDatum(), BTEqualStrategyNumber, GETSTRUCT, HeapTupleIsValid, InvalidOid, lappend_oid(), NIL, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by RelationBuildPublicationDesc().

◆ GetPublication()

Publication* GetPublication ( Oid  pubid)

Definition at line 988 of file pg_publication.c.

989 {
990  HeapTuple tup;
991  Publication *pub;
992  Form_pg_publication pubform;
993 
994  tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
995  if (!HeapTupleIsValid(tup))
996  elog(ERROR, "cache lookup failed for publication %u", pubid);
997 
998  pubform = (Form_pg_publication) GETSTRUCT(tup);
999 
1000  pub = (Publication *) palloc(sizeof(Publication));
1001  pub->oid = pubid;
1002  pub->name = pstrdup(NameStr(pubform->pubname));
1003  pub->alltables = pubform->puballtables;
1004  pub->pubactions.pubinsert = pubform->pubinsert;
1005  pub->pubactions.pubupdate = pubform->pubupdate;
1006  pub->pubactions.pubdelete = pubform->pubdelete;
1007  pub->pubactions.pubtruncate = pubform->pubtruncate;
1008  pub->pubviaroot = pubform->pubviaroot;
1009 
1010  ReleaseSysCache(tup);
1011 
1012  return pub;
1013 }
#define NameStr(name)
Definition: c.h:746
#define elog(elevel,...)
Definition: elog.h:225
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void * palloc(Size size)
Definition: mcxt.c:1317
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
PublicationActions pubactions
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218

References Publication::alltables, elog, ERROR, GETSTRUCT, HeapTupleIsValid, Publication::name, NameStr, ObjectIdGetDatum(), Publication::oid, palloc(), pstrdup(), Publication::pubactions, PublicationActions::pubdelete, PublicationActions::pubinsert, PublicationActions::pubtruncate, PublicationActions::pubupdate, Publication::pubviaroot, ReleaseSysCache(), and SearchSysCache1().

Referenced by GetPublicationByName(), pg_get_publication_tables(), publication_add_relation(), and publication_add_schema().

◆ GetPublicationByName()

Publication* GetPublicationByName ( const char *  pubname,
bool  missing_ok 
)

Definition at line 1019 of file pg_publication.c.

1020 {
1021  Oid oid;
1022 
1023  oid = get_publication_oid(pubname, missing_ok);
1024 
1025  return OidIsValid(oid) ? GetPublication(oid) : NULL;
1026 }
#define OidIsValid(objectId)
Definition: c.h:775
Oid get_publication_oid(const char *pubname, bool missing_ok)
Definition: lsyscache.c:3625
Publication * GetPublication(Oid pubid)

References get_publication_oid(), GetPublication(), and OidIsValid.

Referenced by get_object_address_publication_rel(), get_object_address_publication_schema(), LoadPublications(), and pg_get_publication_tables().

◆ GetPublicationRelations()

List* GetPublicationRelations ( Oid  pubid,
PublicationPartOpt  pub_partopt 
)

Definition at line 698 of file pg_publication.c.

699 {
700  List *result;
701  Relation pubrelsrel;
702  ScanKeyData scankey;
703  SysScanDesc scan;
704  HeapTuple tup;
705 
706  /* Find all publications associated with the relation. */
707  pubrelsrel = table_open(PublicationRelRelationId, AccessShareLock);
708 
709  ScanKeyInit(&scankey,
710  Anum_pg_publication_rel_prpubid,
711  BTEqualStrategyNumber, F_OIDEQ,
712  ObjectIdGetDatum(pubid));
713 
714  scan = systable_beginscan(pubrelsrel, PublicationRelPrpubidIndexId,
715  true, NULL, 1, &scankey);
716 
717  result = NIL;
718  while (HeapTupleIsValid(tup = systable_getnext(scan)))
719  {
721 
722  pubrel = (Form_pg_publication_rel) GETSTRUCT(tup);
723  result = GetPubPartitionOptionRelations(result, pub_partopt,
724  pubrel->prrelid);
725  }
726 
727  systable_endscan(scan);
728  table_close(pubrelsrel, AccessShareLock);
729 
730  /* Now sort and de-duplicate the result list */
731  list_sort(result, list_oid_cmp);
732  list_deduplicate_oid(result);
733 
734  return result;
735 }
void list_sort(List *list, list_sort_comparator cmp)
Definition: list.c:1674
void list_deduplicate_oid(List *list)
Definition: list.c:1495
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition: list.c:1703
List * GetPubPartitionOptionRelations(List *result, PublicationPartOpt pub_partopt, Oid relid)
FormData_pg_publication_rel * Form_pg_publication_rel

References AccessShareLock, BTEqualStrategyNumber, GetPubPartitionOptionRelations(), GETSTRUCT, HeapTupleIsValid, list_deduplicate_oid(), list_oid_cmp(), list_sort(), NIL, ObjectIdGetDatum(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by AlterPublicationOptions(), AlterPublicationSchemas(), AlterPublicationTables(), and pg_get_publication_tables().

◆ GetPublicationSchemas()

List* GetPublicationSchemas ( Oid  pubid)

Definition at line 843 of file pg_publication.c.

844 {
845  List *result = NIL;
846  Relation pubschsrel;
847  ScanKeyData scankey;
848  SysScanDesc scan;
849  HeapTuple tup;
850 
851  /* Find all schemas associated with the publication */
852  pubschsrel = table_open(PublicationNamespaceRelationId, AccessShareLock);
853 
854  ScanKeyInit(&scankey,
855  Anum_pg_publication_namespace_pnpubid,
856  BTEqualStrategyNumber, F_OIDEQ,
857  ObjectIdGetDatum(pubid));
858 
859  scan = systable_beginscan(pubschsrel,
860  PublicationNamespacePnnspidPnpubidIndexId,
861  true, NULL, 1, &scankey);
862  while (HeapTupleIsValid(tup = systable_getnext(scan)))
863  {
865 
867 
868  result = lappend_oid(result, pubsch->pnnspid);
869  }
870 
871  systable_endscan(scan);
872  table_close(pubschsrel, AccessShareLock);
873 
874  return result;
875 }
FormData_pg_publication_namespace * Form_pg_publication_namespace

References AccessShareLock, BTEqualStrategyNumber, GETSTRUCT, HeapTupleIsValid, lappend_oid(), NIL, ObjectIdGetDatum(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by AlterPublicationSchemas(), and GetAllSchemaPublicationRelations().

◆ GetPubPartitionOptionRelations()

List* GetPubPartitionOptionRelations ( List result,
PublicationPartOpt  pub_partopt,
Oid  relid 
)

Definition at line 264 of file pg_publication.c.

266 {
267  if (get_rel_relkind(relid) == RELKIND_PARTITIONED_TABLE &&
268  pub_partopt != PUBLICATION_PART_ROOT)
269  {
270  List *all_parts = find_all_inheritors(relid, NoLock,
271  NULL);
272 
273  if (pub_partopt == PUBLICATION_PART_ALL)
274  result = list_concat(result, all_parts);
275  else if (pub_partopt == PUBLICATION_PART_LEAF)
276  {
277  ListCell *lc;
278 
279  foreach(lc, all_parts)
280  {
281  Oid partOid = lfirst_oid(lc);
282 
283  if (get_rel_relkind(partOid) != RELKIND_PARTITIONED_TABLE)
284  result = lappend_oid(result, partOid);
285  }
286  }
287  else
288  Assert(false);
289  }
290  else
291  result = lappend_oid(result, relid);
292 
293  return result;
294 }
#define NoLock
Definition: lockdefs.h:34
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2003
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
@ PUBLICATION_PART_LEAF
@ PUBLICATION_PART_ROOT
@ PUBLICATION_PART_ALL

References Assert, find_all_inheritors(), get_rel_relkind(), lappend_oid(), lfirst_oid, list_concat(), NoLock, PUBLICATION_PART_ALL, PUBLICATION_PART_LEAF, and PUBLICATION_PART_ROOT.

Referenced by AlterPublicationOptions(), GetPublicationRelations(), GetSchemaPublicationRelations(), publication_add_relation(), and RemovePublicationRelById().

◆ GetRelationPublications()

List* GetRelationPublications ( Oid  relid)

Definition at line 669 of file pg_publication.c.

670 {
671  List *result = NIL;
672  CatCList *pubrellist;
673  int i;
674 
675  /* Find all publications associated with the relation. */
676  pubrellist = SearchSysCacheList1(PUBLICATIONRELMAP,
677  ObjectIdGetDatum(relid));
678  for (i = 0; i < pubrellist->n_members; i++)
679  {
680  HeapTuple tup = &pubrellist->members[i]->tuple;
681  Oid pubid = ((Form_pg_publication_rel) GETSTRUCT(tup))->prpubid;
682 
683  result = lappend_oid(result, pubid);
684  }
685 
686  ReleaseSysCacheList(pubrellist);
687 
688  return result;
689 }
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:180
int n_members
Definition: catcache.h:178
HeapTupleData tuple
Definition: catcache.h:123
#define ReleaseSysCacheList(x)
Definition: syscache.h:129
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:122

References GETSTRUCT, i, lappend_oid(), catclist::members, catclist::n_members, NIL, ObjectIdGetDatum(), ReleaseSysCacheList, SearchSysCacheList1, and catctup::tuple.

Referenced by ATPrepChangePersistence(), get_rel_sync_entry(), GetTopMostAncestorInPublication(), and RelationBuildPublicationDesc().

◆ GetSchemaPublicationRelations()

List* GetSchemaPublicationRelations ( Oid  schemaid,
PublicationPartOpt  pub_partopt 
)

Definition at line 907 of file pg_publication.c.

908 {
909  Relation classRel;
910  ScanKeyData key[1];
911  TableScanDesc scan;
912  HeapTuple tuple;
913  List *result = NIL;
914 
915  Assert(OidIsValid(schemaid));
916 
917  classRel = table_open(RelationRelationId, AccessShareLock);
918 
919  ScanKeyInit(&key[0],
920  Anum_pg_class_relnamespace,
921  BTEqualStrategyNumber, F_OIDEQ,
922  schemaid);
923 
924  /* get all the relations present in the specified schema */
925  scan = table_beginscan_catalog(classRel, 1, key);
926  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
927  {
928  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
929  Oid relid = relForm->oid;
930  char relkind;
931 
932  if (!is_publishable_class(relid, relForm))
933  continue;
934 
935  relkind = get_rel_relkind(relid);
936  if (relkind == RELKIND_RELATION)
937  result = lappend_oid(result, relid);
938  else if (relkind == RELKIND_PARTITIONED_TABLE)
939  {
940  List *partitionrels = NIL;
941 
942  /*
943  * It is quite possible that some of the partitions are in a
944  * different schema than the parent table, so we need to get such
945  * partitions separately.
946  */
947  partitionrels = GetPubPartitionOptionRelations(partitionrels,
948  pub_partopt,
949  relForm->oid);
950  result = list_concat_unique_oid(result, partitionrels);
951  }
952  }
953 
954  table_endscan(scan);
955  table_close(classRel, AccessShareLock);
956  return result;
957 }
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1469

References AccessShareLock, Assert, BTEqualStrategyNumber, ForwardScanDirection, get_rel_relkind(), GetPubPartitionOptionRelations(), GETSTRUCT, heap_getnext(), is_publishable_class(), sort-test::key, lappend_oid(), list_concat_unique_oid(), NIL, OidIsValid, ScanKeyInit(), table_beginscan_catalog(), table_close(), table_endscan(), and table_open().

Referenced by GetAllSchemaPublicationRelations(), publication_add_schema(), and RemovePublicationSchemaById().

◆ GetSchemaPublications()

List* GetSchemaPublications ( Oid  schemaid)

Definition at line 881 of file pg_publication.c.

882 {
883  List *result = NIL;
884  CatCList *pubschlist;
885  int i;
886 
887  /* Find all publications associated with the schema */
888  pubschlist = SearchSysCacheList1(PUBLICATIONNAMESPACEMAP,
889  ObjectIdGetDatum(schemaid));
890  for (i = 0; i < pubschlist->n_members; i++)
891  {
892  HeapTuple tup = &pubschlist->members[i]->tuple;
893  Oid pubid = ((Form_pg_publication_namespace) GETSTRUCT(tup))->pnpubid;
894 
895  result = lappend_oid(result, pubid);
896  }
897 
898  ReleaseSysCacheList(pubschlist);
899 
900  return result;
901 }

References GETSTRUCT, i, lappend_oid(), catclist::members, catclist::n_members, NIL, ObjectIdGetDatum(), ReleaseSysCacheList, SearchSysCacheList1, and catctup::tuple.

Referenced by get_rel_sync_entry(), GetTopMostAncestorInPublication(), and RelationBuildPublicationDesc().

◆ GetTopMostAncestorInPublication()

Oid GetTopMostAncestorInPublication ( Oid  puboid,
List ancestors,
int *  ancestor_level 
)

Definition at line 308 of file pg_publication.c.

309 {
310  ListCell *lc;
311  Oid topmost_relid = InvalidOid;
312  int level = 0;
313 
314  /*
315  * Find the "topmost" ancestor that is in this publication.
316  */
317  foreach(lc, ancestors)
318  {
319  Oid ancestor = lfirst_oid(lc);
320  List *apubids = GetRelationPublications(ancestor);
321  List *aschemaPubids = NIL;
322 
323  level++;
324 
325  if (list_member_oid(apubids, puboid))
326  {
327  topmost_relid = ancestor;
328 
329  if (ancestor_level)
330  *ancestor_level = level;
331  }
332  else
333  {
334  aschemaPubids = GetSchemaPublications(get_rel_namespace(ancestor));
335  if (list_member_oid(aschemaPubids, puboid))
336  {
337  topmost_relid = ancestor;
338 
339  if (ancestor_level)
340  *ancestor_level = level;
341  }
342  }
343 
344  list_free(apubids);
345  list_free(aschemaPubids);
346  }
347 
348  return topmost_relid;
349 }
void list_free(List *list)
Definition: list.c:1546
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:1952
List * GetSchemaPublications(Oid schemaid)
List * GetRelationPublications(Oid relid)

References get_rel_namespace(), GetRelationPublications(), GetSchemaPublications(), InvalidOid, lfirst_oid, list_free(), list_member_oid(), and NIL.

Referenced by get_rel_sync_entry(), pub_collist_contains_invalid_column(), and pub_rf_contains_invalid_column().

◆ is_ancestor_member_tableinfos()

static bool is_ancestor_member_tableinfos ( Oid  ancestor,
List table_infos 
)
static

Definition at line 179 of file pg_publication.c.

180 {
181  ListCell *lc;
182 
183  foreach(lc, table_infos)
184  {
185  Oid relid = ((published_rel *) lfirst(lc))->relid;
186 
187  if (relid == ancestor)
188  return true;
189  }
190 
191  return false;
192 }

References lfirst.

Referenced by filter_partitions().

◆ is_publishable_class()

static bool is_publishable_class ( Oid  relid,
Form_pg_class  reltuple 
)
static

Definition at line 134 of file pg_publication.c.

135 {
136  return (reltuple->relkind == RELKIND_RELATION ||
137  reltuple->relkind == RELKIND_PARTITIONED_TABLE) &&
138  !IsCatalogRelationOid(relid) &&
139  reltuple->relpersistence == RELPERSISTENCE_PERMANENT &&
140  relid >= FirstNormalObjectId;
141 }
bool IsCatalogRelationOid(Oid relid)
Definition: catalog.c:120
#define FirstNormalObjectId
Definition: transam.h:197

References FirstNormalObjectId, and IsCatalogRelationOid().

Referenced by GetAllTablesPublicationRelations(), GetSchemaPublicationRelations(), is_publishable_relation(), and pg_relation_is_publishable().

◆ is_publishable_relation()

bool is_publishable_relation ( Relation  rel)

Definition at line 147 of file pg_publication.c.

148 {
149  return is_publishable_class(RelationGetRelid(rel), rel->rd_rel);
150 }
#define RelationGetRelid(relation)
Definition: rel.h:505

References is_publishable_class(), RelationData::rd_rel, and RelationGetRelid.

Referenced by pgoutput_change(), pgoutput_truncate(), and RelationBuildPublicationDesc().

◆ is_schema_publication()

bool is_schema_publication ( Oid  pubid)

Definition at line 233 of file pg_publication.c.

234 {
235  Relation pubschsrel;
236  ScanKeyData scankey;
237  SysScanDesc scan;
238  HeapTuple tup;
239  bool result = false;
240 
241  pubschsrel = table_open(PublicationNamespaceRelationId, AccessShareLock);
242  ScanKeyInit(&scankey,
243  Anum_pg_publication_namespace_pnpubid,
244  BTEqualStrategyNumber, F_OIDEQ,
245  ObjectIdGetDatum(pubid));
246 
247  scan = systable_beginscan(pubschsrel,
248  PublicationNamespacePnnspidPnpubidIndexId,
249  true, NULL, 1, &scankey);
250  tup = systable_getnext(scan);
251  result = HeapTupleIsValid(tup);
252 
253  systable_endscan(scan);
254  table_close(pubschsrel, AccessShareLock);
255 
256  return result;
257 }

References AccessShareLock, BTEqualStrategyNumber, HeapTupleIsValid, ObjectIdGetDatum(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by AlterPublicationOwner_internal(), and AlterPublicationTables().

◆ pg_get_publication_tables()

Datum pg_get_publication_tables ( PG_FUNCTION_ARGS  )

Definition at line 1034 of file pg_publication.c.

1035 {
1036 #define NUM_PUBLICATION_TABLES_ELEM 4
1037  FuncCallContext *funcctx;
1038  List *table_infos = NIL;
1039 
1040  /* stuff done only on the first call of the function */
1041  if (SRF_IS_FIRSTCALL())
1042  {
1043  TupleDesc tupdesc;
1044  MemoryContext oldcontext;
1045  ArrayType *arr;
1046  Datum *elems;
1047  int nelems,
1048  i;
1049  bool viaroot = false;
1050 
1051  /* create a function context for cross-call persistence */
1052  funcctx = SRF_FIRSTCALL_INIT();
1053 
1054  /* switch to memory context appropriate for multiple function calls */
1055  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1056 
1057  /*
1058  * Deconstruct the parameter into elements where each element is a
1059  * publication name.
1060  */
1061  arr = PG_GETARG_ARRAYTYPE_P(0);
1062  deconstruct_array(arr, TEXTOID, -1, false, TYPALIGN_INT,
1063  &elems, NULL, &nelems);
1064 
1065  /* Get Oids of tables from each publication. */
1066  for (i = 0; i < nelems; i++)
1067  {
1068  Publication *pub_elem;
1069  List *pub_elem_tables = NIL;
1070  ListCell *lc;
1071 
1072  pub_elem = GetPublicationByName(TextDatumGetCString(elems[i]), false);
1073 
1074  /*
1075  * Publications support partitioned tables. If
1076  * publish_via_partition_root is false, all changes are replicated
1077  * using leaf partition identity and schema, so we only need
1078  * those. Otherwise, get the partitioned table itself.
1079  */
1080  if (pub_elem->alltables)
1081  pub_elem_tables = GetAllTablesPublicationRelations(pub_elem->pubviaroot);
1082  else
1083  {
1084  List *relids,
1085  *schemarelids;
1086 
1087  relids = GetPublicationRelations(pub_elem->oid,
1088  pub_elem->pubviaroot ?
1091  schemarelids = GetAllSchemaPublicationRelations(pub_elem->oid,
1092  pub_elem->pubviaroot ?
1095  pub_elem_tables = list_concat_unique_oid(relids, schemarelids);
1096  }
1097 
1098  /*
1099  * Record the published table and the corresponding publication so
1100  * that we can get row filters and column lists later.
1101  *
1102  * When a table is published by multiple publications, to obtain
1103  * all row filters and column lists, the structure related to this
1104  * table will be recorded multiple times.
1105  */
1106  foreach(lc, pub_elem_tables)
1107  {
1108  published_rel *table_info = (published_rel *) palloc(sizeof(published_rel));
1109 
1110  table_info->relid = lfirst_oid(lc);
1111  table_info->pubid = pub_elem->oid;
1112  table_infos = lappend(table_infos, table_info);
1113  }
1114 
1115  /* At least one publication is using publish_via_partition_root. */
1116  if (pub_elem->pubviaroot)
1117  viaroot = true;
1118  }
1119 
1120  /*
1121  * If the publication publishes partition changes via their respective
1122  * root partitioned tables, we must exclude partitions in favor of
1123  * including the root partitioned tables. Otherwise, the function
1124  * could return both the child and parent tables which could cause
1125  * data of the child table to be double-published on the subscriber
1126  * side.
1127  */
1128  if (viaroot)
1129  filter_partitions(table_infos);
1130 
1131  /* Construct a tuple descriptor for the result rows. */
1133  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "pubid",
1134  OIDOID, -1, 0);
1135  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "relid",
1136  OIDOID, -1, 0);
1137  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "attrs",
1138  INT2VECTOROID, -1, 0);
1139  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "qual",
1140  PG_NODE_TREEOID, -1, 0);
1141 
1142  funcctx->tuple_desc = BlessTupleDesc(tupdesc);
1143  funcctx->user_fctx = (void *) table_infos;
1144 
1145  MemoryContextSwitchTo(oldcontext);
1146  }
1147 
1148  /* stuff done on every call of the function */
1149  funcctx = SRF_PERCALL_SETUP();
1150  table_infos = (List *) funcctx->user_fctx;
1151 
1152  if (funcctx->call_cntr < list_length(table_infos))
1153  {
1154  HeapTuple pubtuple = NULL;
1155  HeapTuple rettuple;
1156  Publication *pub;
1157  published_rel *table_info = (published_rel *) list_nth(table_infos, funcctx->call_cntr);
1158  Oid relid = table_info->relid;
1159  Oid schemaid = get_rel_namespace(relid);
1161  bool nulls[NUM_PUBLICATION_TABLES_ELEM] = {0};
1162 
1163  /*
1164  * Form tuple with appropriate data.
1165  */
1166 
1167  pub = GetPublication(table_info->pubid);
1168 
1169  values[0] = ObjectIdGetDatum(pub->oid);
1170  values[1] = ObjectIdGetDatum(relid);
1171 
1172  /*
1173  * We don't consider row filters or column lists for FOR ALL TABLES or
1174  * FOR TABLES IN SCHEMA publications.
1175  */
1176  if (!pub->alltables &&
1177  !SearchSysCacheExists2(PUBLICATIONNAMESPACEMAP,
1178  ObjectIdGetDatum(schemaid),
1179  ObjectIdGetDatum(pub->oid)))
1180  pubtuple = SearchSysCacheCopy2(PUBLICATIONRELMAP,
1181  ObjectIdGetDatum(relid),
1182  ObjectIdGetDatum(pub->oid));
1183 
1184  if (HeapTupleIsValid(pubtuple))
1185  {
1186  /* Lookup the column list attribute. */
1187  values[2] = SysCacheGetAttr(PUBLICATIONRELMAP, pubtuple,
1188  Anum_pg_publication_rel_prattrs,
1189  &(nulls[2]));
1190 
1191  /* Null indicates no filter. */
1192  values[3] = SysCacheGetAttr(PUBLICATIONRELMAP, pubtuple,
1193  Anum_pg_publication_rel_prqual,
1194  &(nulls[3]));
1195  }
1196  else
1197  {
1198  nulls[2] = true;
1199  nulls[3] = true;
1200  }
1201 
1202  /* Show all columns when the column list is not specified. */
1203  if (nulls[2])
1204  {
1205  Relation rel = table_open(relid, AccessShareLock);
1206  int nattnums = 0;
1207  int16 *attnums;
1208  TupleDesc desc = RelationGetDescr(rel);
1209  int i;
1210 
1211  attnums = (int16 *) palloc(desc->natts * sizeof(int16));
1212 
1213  for (i = 0; i < desc->natts; i++)
1214  {
1215  Form_pg_attribute att = TupleDescAttr(desc, i);
1216 
1217  if (att->attisdropped || att->attgenerated)
1218  continue;
1219 
1220  attnums[nattnums++] = att->attnum;
1221  }
1222 
1223  if (nattnums > 0)
1224  {
1225  values[2] = PointerGetDatum(buildint2vector(attnums, nattnums));
1226  nulls[2] = false;
1227  }
1228 
1230  }
1231 
1232  rettuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
1233 
1234  SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(rettuple));
1235  }
1236 
1237  SRF_RETURN_DONE(funcctx);
1238 }
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3619
int16 AttrNumber
Definition: attnum.h:21
static Datum values[MAXATTR]
Definition: bootstrap.c:150
#define TextDatumGetCString(d)
Definition: builtins.h:98
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2158
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
List * lappend(List *list, void *datum)
Definition: list.c:339
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
static int list_length(const List *l)
Definition: pg_list.h:152
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
Publication * GetPublicationByName(const char *pubname, bool missing_ok)
List * GetPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
static void filter_partitions(List *table_infos)
List * GetAllTablesPublicationRelations(bool pubviaroot)
#define NUM_PUBLICATION_TABLES_ELEM
List * GetAllSchemaPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
MemoryContextSwitchTo(old_ctx)
#define RelationGetDescr(relation)
Definition: rel.h:531
void * user_fctx
Definition: funcapi.h:82
uint64 call_cntr
Definition: funcapi.h:65
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
TupleDesc tuple_desc
Definition: funcapi.h:112
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479
#define SearchSysCacheCopy2(cacheId, key1, key2)
Definition: syscache.h:88
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:97
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:651
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References AccessShareLock, Publication::alltables, BlessTupleDesc(), buildint2vector(), FuncCallContext::call_cntr, CreateTemplateTupleDesc(), deconstruct_array(), filter_partitions(), get_rel_namespace(), GetAllSchemaPublicationRelations(), GetAllTablesPublicationRelations(), GetPublication(), GetPublicationByName(), GetPublicationRelations(), heap_form_tuple(), HeapTupleGetDatum(), HeapTupleIsValid, i, if(), lappend(), lfirst_oid, list_concat_unique_oid(), list_length(), list_nth(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, TupleDescData::natts, NIL, NUM_PUBLICATION_TABLES_ELEM, ObjectIdGetDatum(), Publication::oid, palloc(), PG_GETARG_ARRAYTYPE_P, PointerGetDatum(), published_rel::pubid, PUBLICATION_PART_LEAF, PUBLICATION_PART_ROOT, Publication::pubviaroot, RelationGetDescr, published_rel::relid, SearchSysCacheCopy2, SearchSysCacheExists2, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, SysCacheGetAttr(), table_close(), table_open(), TextDatumGetCString, FuncCallContext::tuple_desc, TupleDescAttr, TupleDescInitEntry(), FuncCallContext::user_fctx, and values.

◆ pg_relation_is_publishable()

Datum pg_relation_is_publishable ( PG_FUNCTION_ARGS  )

Definition at line 160 of file pg_publication.c.

161 {
162  Oid relid = PG_GETARG_OID(0);
163  HeapTuple tuple;
164  bool result;
165 
166  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
167  if (!HeapTupleIsValid(tuple))
168  PG_RETURN_NULL();
169  result = is_publishable_class(relid, (Form_pg_class) GETSTRUCT(tuple));
170  ReleaseSysCache(tuple);
171  PG_RETURN_BOOL(result);
172 }
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359

References GETSTRUCT, HeapTupleIsValid, is_publishable_class(), ObjectIdGetDatum(), PG_GETARG_OID, PG_RETURN_BOOL, PG_RETURN_NULL, ReleaseSysCache(), and SearchSysCache1().

◆ pub_collist_to_bitmapset()

Bitmapset* pub_collist_to_bitmapset ( Bitmapset columns,
Datum  pubcols,
MemoryContext  mcxt 
)

Definition at line 559 of file pg_publication.c.

560 {
561  Bitmapset *result = columns;
562  ArrayType *arr;
563  int nelems;
564  int16 *elems;
565  MemoryContext oldcxt = NULL;
566 
567  arr = DatumGetArrayTypeP(pubcols);
568  nelems = ARR_DIMS(arr)[0];
569  elems = (int16 *) ARR_DATA_PTR(arr);
570 
571  /* If a memory context was specified, switch to it. */
572  if (mcxt)
573  oldcxt = MemoryContextSwitchTo(mcxt);
574 
575  for (int i = 0; i < nelems; i++)
576  result = bms_add_member(result, elems[i]);
577 
578  if (mcxt)
579  MemoryContextSwitchTo(oldcxt);
580 
581  return result;
582 }
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_DIMS(a)
Definition: array.h:294
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815

References ARR_DATA_PTR, ARR_DIMS, bms_add_member(), DatumGetArrayTypeP, i, and MemoryContextSwitchTo().

Referenced by AlterPublicationTables(), pgoutput_column_list_init(), and pub_collist_contains_invalid_column().

◆ pub_collist_validate()

Bitmapset* pub_collist_validate ( Relation  targetrel,
List columns 
)

Definition at line 510 of file pg_publication.c.

511 {
512  Bitmapset *set = NULL;
513  ListCell *lc;
514  TupleDesc tupdesc = RelationGetDescr(targetrel);
515 
516  foreach(lc, columns)
517  {
518  char *colname = strVal(lfirst(lc));
519  AttrNumber attnum = get_attnum(RelationGetRelid(targetrel), colname);
520 
521  if (attnum == InvalidAttrNumber)
522  ereport(ERROR,
523  errcode(ERRCODE_UNDEFINED_COLUMN),
524  errmsg("column \"%s\" of relation \"%s\" does not exist",
525  colname, RelationGetRelationName(targetrel)));
526 
528  ereport(ERROR,
529  errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
530  errmsg("cannot use system column \"%s\" in publication column list",
531  colname));
532 
533  if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated)
534  ereport(ERROR,
535  errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
536  errmsg("cannot use generated column \"%s\" in publication column list",
537  colname));
538 
539  if (bms_is_member(attnum, set))
540  ereport(ERROR,
542  errmsg("duplicate column \"%s\" in publication column list",
543  colname));
544 
545  set = bms_add_member(set, attnum);
546  }
547 
548  return set;
549 }
#define AttrNumberIsForUserDefinedAttr(attributeNumber)
Definition: attnum.h:41
#define InvalidAttrNumber
Definition: attnum.h:23
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:858
int16 attnum
Definition: pg_attribute.h:74
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
#define strVal(v)
Definition: value.h:82

References attnum, AttrNumberIsForUserDefinedAttr, bms_add_member(), bms_is_member(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, get_attnum(), InvalidAttrNumber, lfirst, RelationGetDescr, RelationGetRelationName, RelationGetRelid, strVal, and TupleDescAttr.

Referenced by AlterPublicationTables(), and publication_add_relation().

◆ publication_add_relation()

ObjectAddress publication_add_relation ( Oid  pubid,
PublicationRelInfo pri,
bool  if_not_exists 
)

Definition at line 382 of file pg_publication.c.

384 {
385  Relation rel;
386  HeapTuple tup;
387  Datum values[Natts_pg_publication_rel];
388  bool nulls[Natts_pg_publication_rel];
389  Relation targetrel = pri->relation;
390  Oid relid = RelationGetRelid(targetrel);
391  Oid pubreloid;
392  Bitmapset *attnums;
393  Publication *pub = GetPublication(pubid);
394  ObjectAddress myself,
395  referenced;
396  List *relids = NIL;
397  int i;
398 
399  rel = table_open(PublicationRelRelationId, RowExclusiveLock);
400 
401  /*
402  * Check for duplicates. Note that this does not really prevent
403  * duplicates, it's here just to provide nicer error message in common
404  * case. The real protection is the unique key on the catalog.
405  */
406  if (SearchSysCacheExists2(PUBLICATIONRELMAP, ObjectIdGetDatum(relid),
407  ObjectIdGetDatum(pubid)))
408  {
410 
411  if (if_not_exists)
412  return InvalidObjectAddress;
413 
414  ereport(ERROR,
416  errmsg("relation \"%s\" is already member of publication \"%s\"",
417  RelationGetRelationName(targetrel), pub->name)));
418  }
419 
421 
422  /* Validate and translate column names into a Bitmapset of attnums. */
423  attnums = pub_collist_validate(pri->relation, pri->columns);
424 
425  /* Form a tuple. */
426  memset(values, 0, sizeof(values));
427  memset(nulls, false, sizeof(nulls));
428 
429  pubreloid = GetNewOidWithIndex(rel, PublicationRelObjectIndexId,
430  Anum_pg_publication_rel_oid);
431  values[Anum_pg_publication_rel_oid - 1] = ObjectIdGetDatum(pubreloid);
432  values[Anum_pg_publication_rel_prpubid - 1] =
433  ObjectIdGetDatum(pubid);
434  values[Anum_pg_publication_rel_prrelid - 1] =
435  ObjectIdGetDatum(relid);
436 
437  /* Add qualifications, if available */
438  if (pri->whereClause != NULL)
439  values[Anum_pg_publication_rel_prqual - 1] = CStringGetTextDatum(nodeToString(pri->whereClause));
440  else
441  nulls[Anum_pg_publication_rel_prqual - 1] = true;
442 
443  /* Add column list, if available */
444  if (pri->columns)
445  values[Anum_pg_publication_rel_prattrs - 1] = PointerGetDatum(attnumstoint2vector(attnums));
446  else
447  nulls[Anum_pg_publication_rel_prattrs - 1] = true;
448 
449  tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
450 
451  /* Insert tuple into catalog. */
452  CatalogTupleInsert(rel, tup);
453  heap_freetuple(tup);
454 
455  /* Register dependencies as needed */
456  ObjectAddressSet(myself, PublicationRelRelationId, pubreloid);
457 
458  /* Add dependency on the publication */
459  ObjectAddressSet(referenced, PublicationRelationId, pubid);
460  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
461 
462  /* Add dependency on the relation */
463  ObjectAddressSet(referenced, RelationRelationId, relid);
464  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
465 
466  /* Add dependency on the objects mentioned in the qualifications */
467  if (pri->whereClause)
468  recordDependencyOnSingleRelExpr(&myself, pri->whereClause, relid,
470  false);
471 
472  /* Add dependency on the columns, if any are listed */
473  i = -1;
474  while ((i = bms_next_member(attnums, i)) >= 0)
475  {
476  ObjectAddressSubSet(referenced, RelationRelationId, relid, i);
477  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
478  }
479 
480  /* Close the table. */
482 
483  /*
484  * Invalidate relcache so that publication info is rebuilt.
485  *
486  * For the partitioned tables, we must invalidate all partitions contained
487  * in the respective partition hierarchies, not just the one explicitly
488  * mentioned in the publication. This is required because we implicitly
489  * publish the child tables when the parent table is published.
490  */
492  relid);
493 
495 
496  return myself;
497 }
#define CStringGetTextDatum(s)
Definition: builtins.h:97
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:412
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1596
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
#define RowExclusiveLock
Definition: lockdefs.h:38
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
char * nodeToString(const void *obj)
Definition: outfuncs.c:794
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
static int2vector * attnumstoint2vector(Bitmapset *attrs)
Bitmapset * pub_collist_validate(Relation targetrel, List *columns)
static void check_publication_add_relation(Relation targetrel)
void InvalidatePublicationRels(List *relids)

References attnumstoint2vector(), bms_next_member(), CatalogTupleInsert(), check_publication_add_relation(), PublicationRelInfo::columns, CStringGetTextDatum, DEPENDENCY_AUTO, DEPENDENCY_NORMAL, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, GetNewOidWithIndex(), GetPublication(), GetPubPartitionOptionRelations(), heap_form_tuple(), heap_freetuple(), i, InvalidatePublicationRels(), InvalidObjectAddress, Publication::name, NIL, nodeToString(), ObjectAddressSet, ObjectAddressSubSet, ObjectIdGetDatum(), PointerGetDatum(), pub_collist_validate(), PUBLICATION_PART_ALL, recordDependencyOn(), recordDependencyOnSingleRelExpr(), PublicationRelInfo::relation, RelationGetDescr, RelationGetRelationName, RelationGetRelid, RowExclusiveLock, SearchSysCacheExists2, table_close(), table_open(), values, and PublicationRelInfo::whereClause.

Referenced by PublicationAddTables().

◆ publication_add_schema()

ObjectAddress publication_add_schema ( Oid  pubid,
Oid  schemaid,
bool  if_not_exists 
)

Definition at line 588 of file pg_publication.c.

589 {
590  Relation rel;
591  HeapTuple tup;
592  Datum values[Natts_pg_publication_namespace];
593  bool nulls[Natts_pg_publication_namespace];
594  Oid psschid;
595  Publication *pub = GetPublication(pubid);
596  List *schemaRels = NIL;
597  ObjectAddress myself,
598  referenced;
599 
600  rel = table_open(PublicationNamespaceRelationId, RowExclusiveLock);
601 
602  /*
603  * Check for duplicates. Note that this does not really prevent
604  * duplicates, it's here just to provide nicer error message in common
605  * case. The real protection is the unique key on the catalog.
606  */
607  if (SearchSysCacheExists2(PUBLICATIONNAMESPACEMAP,
608  ObjectIdGetDatum(schemaid),
609  ObjectIdGetDatum(pubid)))
610  {
612 
613  if (if_not_exists)
614  return InvalidObjectAddress;
615 
616  ereport(ERROR,
618  errmsg("schema \"%s\" is already member of publication \"%s\"",
619  get_namespace_name(schemaid), pub->name)));
620  }
621 
623 
624  /* Form a tuple */
625  memset(values, 0, sizeof(values));
626  memset(nulls, false, sizeof(nulls));
627 
628  psschid = GetNewOidWithIndex(rel, PublicationNamespaceObjectIndexId,
629  Anum_pg_publication_namespace_oid);
630  values[Anum_pg_publication_namespace_oid - 1] = ObjectIdGetDatum(psschid);
631  values[Anum_pg_publication_namespace_pnpubid - 1] =
632  ObjectIdGetDatum(pubid);
633  values[Anum_pg_publication_namespace_pnnspid - 1] =
634  ObjectIdGetDatum(schemaid);
635 
636  tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
637 
638  /* Insert tuple into catalog */
639  CatalogTupleInsert(rel, tup);
640  heap_freetuple(tup);
641 
642  ObjectAddressSet(myself, PublicationNamespaceRelationId, psschid);
643 
644  /* Add dependency on the publication */
645  ObjectAddressSet(referenced, PublicationRelationId, pubid);
646  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
647 
648  /* Add dependency on the schema */
649  ObjectAddressSet(referenced, NamespaceRelationId, schemaid);
650  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
651 
652  /* Close the table */
654 
655  /*
656  * Invalidate relcache so that publication info is rebuilt. See
657  * publication_add_relation for why we need to consider all the
658  * partitions.
659  */
660  schemaRels = GetSchemaPublicationRelations(schemaid,
662  InvalidatePublicationRels(schemaRels);
663 
664  return myself;
665 }
static void check_publication_add_schema(Oid schemaid)

References CatalogTupleInsert(), check_publication_add_schema(), DEPENDENCY_AUTO, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, get_namespace_name(), GetNewOidWithIndex(), GetPublication(), GetSchemaPublicationRelations(), heap_form_tuple(), heap_freetuple(), InvalidatePublicationRels(), InvalidObjectAddress, Publication::name, NIL, ObjectAddressSet, ObjectIdGetDatum(), PUBLICATION_PART_ALL, recordDependencyOn(), RelationGetDescr, RowExclusiveLock, SearchSysCacheExists2, table_close(), table_open(), and values.

Referenced by PublicationAddSchemas().