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)
 
bool check_and_fetch_column_list (Publication *pub, Oid relid, MemoryContext mcxt, Bitmapset **cols)
 
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)
 
Bitmapsetpub_form_cols_map (Relation relation, bool include_gencols)
 
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 405 of file pg_publication.c.

406{
407 int2vector *result;
408 int n = bms_num_members(attrs);
409 int i = -1;
410 int j = 0;
411
412 result = buildint2vector(NULL, n);
413
414 while ((i = bms_next_member(attrs, i)) >= 0)
415 {
417
418 result->values[j++] = (int16) i;
419 }
420
421 return result;
422}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:751
#define Assert(condition)
Definition: c.h:815
int16_t int16
Definition: c.h:483
#define PG_INT16_MAX
Definition: c.h:543
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:114
int j
Definition: isn.c:73
int i
Definition: isn.c:72
Definition: c.h:672
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:679

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

Referenced by publication_add_relation().

◆ check_and_fetch_column_list()

bool check_and_fetch_column_list ( Publication pub,
Oid  relid,
MemoryContext  mcxt,
Bitmapset **  cols 
)

Definition at line 268 of file pg_publication.c.

270{
271 HeapTuple cftuple;
272 bool found = false;
273
274 if (pub->alltables)
275 return false;
276
277 cftuple = SearchSysCache2(PUBLICATIONRELMAP,
278 ObjectIdGetDatum(relid),
279 ObjectIdGetDatum(pub->oid));
280 if (HeapTupleIsValid(cftuple))
281 {
282 Datum cfdatum;
283 bool isnull;
284
285 /* Lookup the column list attribute. */
286 cfdatum = SysCacheGetAttr(PUBLICATIONRELMAP, cftuple,
287 Anum_pg_publication_rel_prattrs, &isnull);
288
289 /* Was a column list found? */
290 if (!isnull)
291 {
292 /* Build the column list bitmap in the given memory context. */
293 if (cols)
294 *cols = pub_collist_to_bitmapset(*cols, cfdatum, mcxt);
295
296 found = true;
297 }
298
299 ReleaseSysCache(cftuple);
300 }
301
302 return found;
303}
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
Bitmapset * pub_collist_to_bitmapset(Bitmapset *columns, Datum pubcols, MemoryContext mcxt)
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:232

References Publication::alltables, HeapTupleIsValid, ObjectIdGetDatum(), Publication::oid, pub_collist_to_bitmapset(), ReleaseSysCache(), SearchSysCache2(), and SysCacheGetAttr().

Referenced by check_and_init_gencol(), pgoutput_column_list_init(), and pub_contains_invalid_column().

◆ 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)
62 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
63 errmsg("cannot add relation \"%s\" to publication",
64 RelationGetRelationName(targetrel)),
66
67 /* Can't be system table */
68 if (IsCatalogRelation(targetrel))
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)
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)
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))
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))
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:230
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:212
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3687

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:107
#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:32
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 1026 of file pg_publication.c.

1027{
1028 List *result = NIL;
1029 List *pubschemalist = GetPublicationSchemas(pubid);
1030 ListCell *cell;
1031
1032 foreach(cell, pubschemalist)
1033 {
1034 Oid schemaid = lfirst_oid(cell);
1035 List *schemaRels = NIL;
1036
1037 schemaRels = GetSchemaPublicationRelations(schemaid, pub_partopt);
1038 result = list_concat(result, schemaRels);
1039 }
1040
1041 return result;
1042}
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 844 of file pg_publication.c.

845{
846 Relation classRel;
847 ScanKeyData key[1];
848 TableScanDesc scan;
849 HeapTuple tuple;
850 List *result = NIL;
851
852 classRel = table_open(RelationRelationId, AccessShareLock);
853
854 ScanKeyInit(&key[0],
855 Anum_pg_class_relkind,
856 BTEqualStrategyNumber, F_CHAREQ,
857 CharGetDatum(RELKIND_RELATION));
858
859 scan = table_beginscan_catalog(classRel, 1, key);
860
861 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
862 {
863 Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
864 Oid relid = relForm->oid;
865
866 if (is_publishable_class(relid, relForm) &&
867 !(relForm->relispartition && pubviaroot))
868 result = lappend_oid(result, relid);
869 }
870
871 table_endscan(scan);
872
873 if (pubviaroot)
874 {
875 ScanKeyInit(&key[0],
876 Anum_pg_class_relkind,
877 BTEqualStrategyNumber, F_CHAREQ,
878 CharGetDatum(RELKIND_PARTITIONED_TABLE));
879
880 scan = table_beginscan_catalog(classRel, 1, key);
881
882 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
883 {
884 Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
885 Oid relid = relForm->oid;
886
887 if (is_publishable_class(relid, relForm) &&
888 !relForm->relispartition)
889 result = lappend_oid(result, relid);
890 }
891
892 table_endscan(scan);
893 }
894
895 table_close(classRel, AccessShareLock);
896 return result;
897}
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1264
#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:127
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:1024

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 803 of file pg_publication.c.

804{
805 List *result;
806 Relation rel;
807 ScanKeyData scankey;
808 SysScanDesc scan;
809 HeapTuple tup;
810
811 /* Find all publications that are marked as for all tables. */
812 rel = table_open(PublicationRelationId, AccessShareLock);
813
814 ScanKeyInit(&scankey,
815 Anum_pg_publication_puballtables,
816 BTEqualStrategyNumber, F_BOOLEQ,
817 BoolGetDatum(true));
818
819 scan = systable_beginscan(rel, InvalidOid, false,
820 NULL, 1, &scankey);
821
822 result = NIL;
823 while (HeapTupleIsValid(tup = systable_getnext(scan)))
824 {
825 Oid oid = ((Form_pg_publication) GETSTRUCT(tup))->oid;
826
827 result = lappend_oid(result, oid);
828 }
829
830 systable_endscan(scan);
832
833 return result;
834}
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:606
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:513
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
FormData_pg_publication * Form_pg_publication
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
#define InvalidOid
Definition: postgres_ext.h:37

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 1050 of file pg_publication.c.

1051{
1052 HeapTuple tup;
1053 Publication *pub;
1054 Form_pg_publication pubform;
1055
1056 tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
1057 if (!HeapTupleIsValid(tup))
1058 elog(ERROR, "cache lookup failed for publication %u", pubid);
1059
1060 pubform = (Form_pg_publication) GETSTRUCT(tup);
1061
1062 pub = (Publication *) palloc(sizeof(Publication));
1063 pub->oid = pubid;
1064 pub->name = pstrdup(NameStr(pubform->pubname));
1065 pub->alltables = pubform->puballtables;
1066 pub->pubactions.pubinsert = pubform->pubinsert;
1067 pub->pubactions.pubupdate = pubform->pubupdate;
1068 pub->pubactions.pubdelete = pubform->pubdelete;
1069 pub->pubactions.pubtruncate = pubform->pubtruncate;
1070 pub->pubviaroot = pubform->pubviaroot;
1071 pub->pubgencols = pubform->pubgencols;
1072
1073 ReleaseSysCache(tup);
1074
1075 return pub;
1076}
#define NameStr(name)
Definition: c.h:703
#define elog(elevel,...)
Definition: elog.h:225
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void * palloc(Size size)
Definition: mcxt.c:1317
PublicationActions pubactions
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

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

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

◆ GetPublicationByName()

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

Definition at line 1082 of file pg_publication.c.

1083{
1084 Oid oid;
1085
1086 oid = get_publication_oid(pubname, missing_ok);
1087
1088 return OidIsValid(oid) ? GetPublication(oid) : NULL;
1089}
#define OidIsValid(objectId)
Definition: c.h:732
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 760 of file pg_publication.c.

761{
762 List *result;
763 Relation pubrelsrel;
764 ScanKeyData scankey;
765 SysScanDesc scan;
766 HeapTuple tup;
767
768 /* Find all publications associated with the relation. */
769 pubrelsrel = table_open(PublicationRelRelationId, AccessShareLock);
770
771 ScanKeyInit(&scankey,
772 Anum_pg_publication_rel_prpubid,
773 BTEqualStrategyNumber, F_OIDEQ,
774 ObjectIdGetDatum(pubid));
775
776 scan = systable_beginscan(pubrelsrel, PublicationRelPrpubidIndexId,
777 true, NULL, 1, &scankey);
778
779 result = NIL;
780 while (HeapTupleIsValid(tup = systable_getnext(scan)))
781 {
783
784 pubrel = (Form_pg_publication_rel) GETSTRUCT(tup);
785 result = GetPubPartitionOptionRelations(result, pub_partopt,
786 pubrel->prrelid);
787 }
788
789 systable_endscan(scan);
790 table_close(pubrelsrel, AccessShareLock);
791
792 /* Now sort and de-duplicate the result list */
793 list_sort(result, list_oid_cmp);
794 list_deduplicate_oid(result);
795
796 return result;
797}
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 905 of file pg_publication.c.

906{
907 List *result = NIL;
908 Relation pubschsrel;
909 ScanKeyData scankey;
910 SysScanDesc scan;
911 HeapTuple tup;
912
913 /* Find all schemas associated with the publication */
914 pubschsrel = table_open(PublicationNamespaceRelationId, AccessShareLock);
915
916 ScanKeyInit(&scankey,
917 Anum_pg_publication_namespace_pnpubid,
918 BTEqualStrategyNumber, F_OIDEQ,
919 ObjectIdGetDatum(pubid));
920
921 scan = systable_beginscan(pubschsrel,
922 PublicationNamespacePnnspidPnpubidIndexId,
923 true, NULL, 1, &scankey);
924 while (HeapTupleIsValid(tup = systable_getnext(scan)))
925 {
927
929
930 result = lappend_oid(result, pubsch->pnnspid);
931 }
932
933 systable_endscan(scan);
934 table_close(pubschsrel, AccessShareLock);
935
936 return result;
937}
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 310 of file pg_publication.c.

312{
313 if (get_rel_relkind(relid) == RELKIND_PARTITIONED_TABLE &&
314 pub_partopt != PUBLICATION_PART_ROOT)
315 {
316 List *all_parts = find_all_inheritors(relid, NoLock,
317 NULL);
318
319 if (pub_partopt == PUBLICATION_PART_ALL)
320 result = list_concat(result, all_parts);
321 else if (pub_partopt == PUBLICATION_PART_LEAF)
322 {
323 ListCell *lc;
324
325 foreach(lc, all_parts)
326 {
327 Oid partOid = lfirst_oid(lc);
328
329 if (get_rel_relkind(partOid) != RELKIND_PARTITIONED_TABLE)
330 result = lappend_oid(result, partOid);
331 }
332 }
333 else
334 Assert(false);
335 }
336 else
337 result = lappend_oid(result, relid);
338
339 return result;
340}
#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 731 of file pg_publication.c.

732{
733 List *result = NIL;
734 CatCList *pubrellist;
735 int i;
736
737 /* Find all publications associated with the relation. */
738 pubrellist = SearchSysCacheList1(PUBLICATIONRELMAP,
739 ObjectIdGetDatum(relid));
740 for (i = 0; i < pubrellist->n_members; i++)
741 {
742 HeapTuple tup = &pubrellist->members[i]->tuple;
743 Oid pubid = ((Form_pg_publication_rel) GETSTRUCT(tup))->prpubid;
744
745 result = lappend_oid(result, pubid);
746 }
747
748 ReleaseSysCacheList(pubrellist);
749
750 return result;
751}
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:134
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:127

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 969 of file pg_publication.c.

970{
971 Relation classRel;
972 ScanKeyData key[1];
973 TableScanDesc scan;
974 HeapTuple tuple;
975 List *result = NIL;
976
977 Assert(OidIsValid(schemaid));
978
979 classRel = table_open(RelationRelationId, AccessShareLock);
980
981 ScanKeyInit(&key[0],
982 Anum_pg_class_relnamespace,
983 BTEqualStrategyNumber, F_OIDEQ,
984 schemaid);
985
986 /* get all the relations present in the specified schema */
987 scan = table_beginscan_catalog(classRel, 1, key);
988 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
989 {
990 Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
991 Oid relid = relForm->oid;
992 char relkind;
993
994 if (!is_publishable_class(relid, relForm))
995 continue;
996
997 relkind = get_rel_relkind(relid);
998 if (relkind == RELKIND_RELATION)
999 result = lappend_oid(result, relid);
1000 else if (relkind == RELKIND_PARTITIONED_TABLE)
1001 {
1002 List *partitionrels = NIL;
1003
1004 /*
1005 * It is quite possible that some of the partitions are in a
1006 * different schema than the parent table, so we need to get such
1007 * partitions separately.
1008 */
1009 partitionrels = GetPubPartitionOptionRelations(partitionrels,
1010 pub_partopt,
1011 relForm->oid);
1012 result = list_concat_unique_oid(result, partitionrels);
1013 }
1014 }
1015
1016 table_endscan(scan);
1017 table_close(classRel, AccessShareLock);
1018 return result;
1019}
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 943 of file pg_publication.c.

944{
945 List *result = NIL;
946 CatCList *pubschlist;
947 int i;
948
949 /* Find all publications associated with the schema */
950 pubschlist = SearchSysCacheList1(PUBLICATIONNAMESPACEMAP,
951 ObjectIdGetDatum(schemaid));
952 for (i = 0; i < pubschlist->n_members; i++)
953 {
954 HeapTuple tup = &pubschlist->members[i]->tuple;
955 Oid pubid = ((Form_pg_publication_namespace) GETSTRUCT(tup))->pnpubid;
956
957 result = lappend_oid(result, pubid);
958 }
959
960 ReleaseSysCacheList(pubschlist);
961
962 return result;
963}

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 354 of file pg_publication.c.

355{
356 ListCell *lc;
357 Oid topmost_relid = InvalidOid;
358 int level = 0;
359
360 /*
361 * Find the "topmost" ancestor that is in this publication.
362 */
363 foreach(lc, ancestors)
364 {
365 Oid ancestor = lfirst_oid(lc);
366 List *apubids = GetRelationPublications(ancestor);
367 List *aschemaPubids = NIL;
368
369 level++;
370
371 if (list_member_oid(apubids, puboid))
372 {
373 topmost_relid = ancestor;
374
375 if (ancestor_level)
376 *ancestor_level = level;
377 }
378 else
379 {
380 aschemaPubids = GetSchemaPublications(get_rel_namespace(ancestor));
381 if (list_member_oid(aschemaPubids, puboid))
382 {
383 topmost_relid = ancestor;
384
385 if (ancestor_level)
386 *ancestor_level = level;
387 }
388 }
389
390 list_free(apubids);
391 list_free(aschemaPubids);
392 }
393
394 return topmost_relid;
395}
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 * GetRelationPublications(Oid relid)
List * GetSchemaPublications(Oid schemaid)

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

Referenced by get_rel_sync_entry(), pub_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{
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 1097 of file pg_publication.c.

1098{
1099#define NUM_PUBLICATION_TABLES_ELEM 4
1100 FuncCallContext *funcctx;
1101 List *table_infos = NIL;
1102
1103 /* stuff done only on the first call of the function */
1104 if (SRF_IS_FIRSTCALL())
1105 {
1106 TupleDesc tupdesc;
1107 MemoryContext oldcontext;
1108 ArrayType *arr;
1109 Datum *elems;
1110 int nelems,
1111 i;
1112 bool viaroot = false;
1113
1114 /* create a function context for cross-call persistence */
1115 funcctx = SRF_FIRSTCALL_INIT();
1116
1117 /* switch to memory context appropriate for multiple function calls */
1118 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1119
1120 /*
1121 * Deconstruct the parameter into elements where each element is a
1122 * publication name.
1123 */
1124 arr = PG_GETARG_ARRAYTYPE_P(0);
1125 deconstruct_array_builtin(arr, TEXTOID, &elems, NULL, &nelems);
1126
1127 /* Get Oids of tables from each publication. */
1128 for (i = 0; i < nelems; i++)
1129 {
1130 Publication *pub_elem;
1131 List *pub_elem_tables = NIL;
1132 ListCell *lc;
1133
1134 pub_elem = GetPublicationByName(TextDatumGetCString(elems[i]), false);
1135
1136 /*
1137 * Publications support partitioned tables. If
1138 * publish_via_partition_root is false, all changes are replicated
1139 * using leaf partition identity and schema, so we only need
1140 * those. Otherwise, get the partitioned table itself.
1141 */
1142 if (pub_elem->alltables)
1143 pub_elem_tables = GetAllTablesPublicationRelations(pub_elem->pubviaroot);
1144 else
1145 {
1146 List *relids,
1147 *schemarelids;
1148
1149 relids = GetPublicationRelations(pub_elem->oid,
1150 pub_elem->pubviaroot ?
1153 schemarelids = GetAllSchemaPublicationRelations(pub_elem->oid,
1154 pub_elem->pubviaroot ?
1157 pub_elem_tables = list_concat_unique_oid(relids, schemarelids);
1158 }
1159
1160 /*
1161 * Record the published table and the corresponding publication so
1162 * that we can get row filters and column lists later.
1163 *
1164 * When a table is published by multiple publications, to obtain
1165 * all row filters and column lists, the structure related to this
1166 * table will be recorded multiple times.
1167 */
1168 foreach(lc, pub_elem_tables)
1169 {
1170 published_rel *table_info = (published_rel *) palloc(sizeof(published_rel));
1171
1172 table_info->relid = lfirst_oid(lc);
1173 table_info->pubid = pub_elem->oid;
1174 table_infos = lappend(table_infos, table_info);
1175 }
1176
1177 /* At least one publication is using publish_via_partition_root. */
1178 if (pub_elem->pubviaroot)
1179 viaroot = true;
1180 }
1181
1182 /*
1183 * If the publication publishes partition changes via their respective
1184 * root partitioned tables, we must exclude partitions in favor of
1185 * including the root partitioned tables. Otherwise, the function
1186 * could return both the child and parent tables which could cause
1187 * data of the child table to be double-published on the subscriber
1188 * side.
1189 */
1190 if (viaroot)
1191 filter_partitions(table_infos);
1192
1193 /* Construct a tuple descriptor for the result rows. */
1195 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "pubid",
1196 OIDOID, -1, 0);
1197 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "relid",
1198 OIDOID, -1, 0);
1199 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "attrs",
1200 INT2VECTOROID, -1, 0);
1201 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "qual",
1202 PG_NODE_TREEOID, -1, 0);
1203
1204 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
1205 funcctx->user_fctx = table_infos;
1206
1207 MemoryContextSwitchTo(oldcontext);
1208 }
1209
1210 /* stuff done on every call of the function */
1211 funcctx = SRF_PERCALL_SETUP();
1212 table_infos = (List *) funcctx->user_fctx;
1213
1214 if (funcctx->call_cntr < list_length(table_infos))
1215 {
1216 HeapTuple pubtuple = NULL;
1217 HeapTuple rettuple;
1218 Publication *pub;
1219 published_rel *table_info = (published_rel *) list_nth(table_infos, funcctx->call_cntr);
1220 Oid relid = table_info->relid;
1221 Oid schemaid = get_rel_namespace(relid);
1223 bool nulls[NUM_PUBLICATION_TABLES_ELEM] = {0};
1224
1225 /*
1226 * Form tuple with appropriate data.
1227 */
1228
1229 pub = GetPublication(table_info->pubid);
1230
1231 values[0] = ObjectIdGetDatum(pub->oid);
1232 values[1] = ObjectIdGetDatum(relid);
1233
1234 /*
1235 * We don't consider row filters or column lists for FOR ALL TABLES or
1236 * FOR TABLES IN SCHEMA publications.
1237 */
1238 if (!pub->alltables &&
1239 !SearchSysCacheExists2(PUBLICATIONNAMESPACEMAP,
1240 ObjectIdGetDatum(schemaid),
1241 ObjectIdGetDatum(pub->oid)))
1242 pubtuple = SearchSysCacheCopy2(PUBLICATIONRELMAP,
1243 ObjectIdGetDatum(relid),
1244 ObjectIdGetDatum(pub->oid));
1245
1246 if (HeapTupleIsValid(pubtuple))
1247 {
1248 /* Lookup the column list attribute. */
1249 values[2] = SysCacheGetAttr(PUBLICATIONRELMAP, pubtuple,
1250 Anum_pg_publication_rel_prattrs,
1251 &(nulls[2]));
1252
1253 /* Null indicates no filter. */
1254 values[3] = SysCacheGetAttr(PUBLICATIONRELMAP, pubtuple,
1255 Anum_pg_publication_rel_prqual,
1256 &(nulls[3]));
1257 }
1258 else
1259 {
1260 nulls[2] = true;
1261 nulls[3] = true;
1262 }
1263
1264 /* Show all columns when the column list is not specified. */
1265 if (nulls[2])
1266 {
1267 Relation rel = table_open(relid, AccessShareLock);
1268 int nattnums = 0;
1269 int16 *attnums;
1270 TupleDesc desc = RelationGetDescr(rel);
1271 int i;
1272
1273 attnums = (int16 *) palloc(desc->natts * sizeof(int16));
1274
1275 for (i = 0; i < desc->natts; i++)
1276 {
1277 Form_pg_attribute att = TupleDescAttr(desc, i);
1278
1279 if (att->attisdropped || (att->attgenerated && !pub->pubgencols))
1280 continue;
1281
1282 attnums[nattnums++] = att->attnum;
1283 }
1284
1285 if (nattnums > 0)
1286 {
1287 values[2] = PointerGetDatum(buildint2vector(attnums, nattnums));
1288 nulls[2] = false;
1289 }
1290
1292 }
1293
1294 rettuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
1295
1296 SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(rettuple));
1297 }
1298
1299 SRF_RETURN_DONE(funcctx);
1300}
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3697
int16 AttrNumber
Definition: attnum.h:21
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define TextDatumGetCString(d)
Definition: builtins.h:98
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2258
#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:1117
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
List * lappend(List *list, void *datum)
Definition: list.c:339
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
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
List * GetAllSchemaPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
Publication * GetPublicationByName(const char *pubname, bool missing_ok)
static void filter_partitions(List *table_infos)
List * GetAllTablesPublicationRelations(bool pubviaroot)
#define NUM_PUBLICATION_TABLES_ELEM
List * GetPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
#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
#define SearchSysCacheCopy2(cacheId, key1, key2)
Definition: syscache.h:93
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:102
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:164
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:798
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:153

References AccessShareLock, Publication::alltables, BlessTupleDesc(), buildint2vector(), FuncCallContext::call_cntr, CreateTemplateTupleDesc(), deconstruct_array_builtin(), 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(), Publication::pubgencols, 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))
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 597 of file pg_publication.c.

598{
599 Bitmapset *result = columns;
600 ArrayType *arr;
601 int nelems;
602 int16 *elems;
603 MemoryContext oldcxt = NULL;
604
605 arr = DatumGetArrayTypeP(pubcols);
606 nelems = ARR_DIMS(arr)[0];
607 elems = (int16 *) ARR_DATA_PTR(arr);
608
609 /* If a memory context was specified, switch to it. */
610 if (mcxt)
611 oldcxt = MemoryContextSwitchTo(mcxt);
612
613 for (int i = 0; i < nelems; i++)
614 result = bms_add_member(result, elems[i]);
615
616 if (mcxt)
617 MemoryContextSwitchTo(oldcxt);
618
619 return result;
620}
#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(), and check_and_fetch_column_list().

◆ pub_collist_validate()

Bitmapset * pub_collist_validate ( Relation  targetrel,
List columns 
)

Definition at line 555 of file pg_publication.c.

556{
557 Bitmapset *set = NULL;
558 ListCell *lc;
559
560 foreach(lc, columns)
561 {
562 char *colname = strVal(lfirst(lc));
563 AttrNumber attnum = get_attnum(RelationGetRelid(targetrel), colname);
564
567 errcode(ERRCODE_UNDEFINED_COLUMN),
568 errmsg("column \"%s\" of relation \"%s\" does not exist",
569 colname, RelationGetRelationName(targetrel)));
570
573 errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
574 errmsg("cannot use system column \"%s\" in publication column list",
575 colname));
576
577 if (bms_is_member(attnum, set))
580 errmsg("duplicate column \"%s\" in publication column list",
581 colname));
582
583 set = bms_add_member(set, attnum);
584 }
585
586 return set;
587}
#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:30
#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, RelationGetRelationName, RelationGetRelid, and strVal.

Referenced by AlterPublicationTables(), and publication_add_relation().

◆ pub_form_cols_map()

Bitmapset * pub_form_cols_map ( Relation  relation,
bool  include_gencols 
)

Definition at line 628 of file pg_publication.c.

629{
630 Bitmapset *result = NULL;
631 TupleDesc desc = RelationGetDescr(relation);
632
633 for (int i = 0; i < desc->natts; i++)
634 {
635 Form_pg_attribute att = TupleDescAttr(desc, i);
636
637 if (att->attisdropped || (att->attgenerated && !include_gencols))
638 continue;
639
640 result = bms_add_member(result, att->attnum);
641 }
642
643 return result;
644}

References bms_add_member(), i, TupleDescData::natts, RelationGetDescr, and TupleDescAttr().

Referenced by pgoutput_column_list_init().

◆ publication_add_relation()

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

Definition at line 428 of file pg_publication.c.

430{
431 Relation rel;
432 HeapTuple tup;
433 Datum values[Natts_pg_publication_rel];
434 bool nulls[Natts_pg_publication_rel];
435 Relation targetrel = pri->relation;
436 Oid relid = RelationGetRelid(targetrel);
437 Oid pubreloid;
438 Bitmapset *attnums;
439 Publication *pub = GetPublication(pubid);
440 ObjectAddress myself,
441 referenced;
442 List *relids = NIL;
443 int i;
444
445 rel = table_open(PublicationRelRelationId, RowExclusiveLock);
446
447 /*
448 * Check for duplicates. Note that this does not really prevent
449 * duplicates, it's here just to provide nicer error message in common
450 * case. The real protection is the unique key on the catalog.
451 */
452 if (SearchSysCacheExists2(PUBLICATIONRELMAP, ObjectIdGetDatum(relid),
453 ObjectIdGetDatum(pubid)))
454 {
456
457 if (if_not_exists)
459
462 errmsg("relation \"%s\" is already member of publication \"%s\"",
463 RelationGetRelationName(targetrel), pub->name)));
464 }
465
467
468 /* Validate and translate column names into a Bitmapset of attnums. */
469 attnums = pub_collist_validate(pri->relation, pri->columns);
470
471 /* Form a tuple. */
472 memset(values, 0, sizeof(values));
473 memset(nulls, false, sizeof(nulls));
474
475 pubreloid = GetNewOidWithIndex(rel, PublicationRelObjectIndexId,
476 Anum_pg_publication_rel_oid);
477 values[Anum_pg_publication_rel_oid - 1] = ObjectIdGetDatum(pubreloid);
478 values[Anum_pg_publication_rel_prpubid - 1] =
479 ObjectIdGetDatum(pubid);
480 values[Anum_pg_publication_rel_prrelid - 1] =
481 ObjectIdGetDatum(relid);
482
483 /* Add qualifications, if available */
484 if (pri->whereClause != NULL)
485 values[Anum_pg_publication_rel_prqual - 1] = CStringGetTextDatum(nodeToString(pri->whereClause));
486 else
487 nulls[Anum_pg_publication_rel_prqual - 1] = true;
488
489 /* Add column list, if available */
490 if (pri->columns)
491 values[Anum_pg_publication_rel_prattrs - 1] = PointerGetDatum(attnumstoint2vector(attnums));
492 else
493 nulls[Anum_pg_publication_rel_prattrs - 1] = true;
494
495 tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
496
497 /* Insert tuple into catalog. */
498 CatalogTupleInsert(rel, tup);
499 heap_freetuple(tup);
500
501 /* Register dependencies as needed */
502 ObjectAddressSet(myself, PublicationRelRelationId, pubreloid);
503
504 /* Add dependency on the publication */
505 ObjectAddressSet(referenced, PublicationRelationId, pubid);
506 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
507
508 /* Add dependency on the relation */
509 ObjectAddressSet(referenced, RelationRelationId, relid);
510 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
511
512 /* Add dependency on the objects mentioned in the qualifications */
513 if (pri->whereClause)
514 recordDependencyOnSingleRelExpr(&myself, pri->whereClause, relid,
516 false);
517
518 /* Add dependency on the columns, if any are listed */
519 i = -1;
520 while ((i = bms_next_member(attnums, i)) >= 0)
521 {
522 ObjectAddressSubSet(referenced, RelationRelationId, relid, i);
523 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
524 }
525
526 /* Close the table. */
528
529 /*
530 * Invalidate relcache so that publication info is rebuilt.
531 *
532 * For the partitioned tables, we must invalidate all partitions contained
533 * in the respective partition hierarchies, not just the one explicitly
534 * mentioned in the publication. This is required because we implicitly
535 * publish the child tables when the parent table is published.
536 */
538 relid);
539
541
542 return myself;
543}
#define CStringGetTextDatum(s)
Definition: builtins.h:97
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
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:1435
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:45
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 650 of file pg_publication.c.

651{
652 Relation rel;
653 HeapTuple tup;
654 Datum values[Natts_pg_publication_namespace];
655 bool nulls[Natts_pg_publication_namespace];
656 Oid psschid;
657 Publication *pub = GetPublication(pubid);
658 List *schemaRels = NIL;
659 ObjectAddress myself,
660 referenced;
661
662 rel = table_open(PublicationNamespaceRelationId, RowExclusiveLock);
663
664 /*
665 * Check for duplicates. Note that this does not really prevent
666 * duplicates, it's here just to provide nicer error message in common
667 * case. The real protection is the unique key on the catalog.
668 */
669 if (SearchSysCacheExists2(PUBLICATIONNAMESPACEMAP,
670 ObjectIdGetDatum(schemaid),
671 ObjectIdGetDatum(pubid)))
672 {
674
675 if (if_not_exists)
677
680 errmsg("schema \"%s\" is already member of publication \"%s\"",
681 get_namespace_name(schemaid), pub->name)));
682 }
683
685
686 /* Form a tuple */
687 memset(values, 0, sizeof(values));
688 memset(nulls, false, sizeof(nulls));
689
690 psschid = GetNewOidWithIndex(rel, PublicationNamespaceObjectIndexId,
691 Anum_pg_publication_namespace_oid);
692 values[Anum_pg_publication_namespace_oid - 1] = ObjectIdGetDatum(psschid);
693 values[Anum_pg_publication_namespace_pnpubid - 1] =
694 ObjectIdGetDatum(pubid);
695 values[Anum_pg_publication_namespace_pnnspid - 1] =
696 ObjectIdGetDatum(schemaid);
697
698 tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
699
700 /* Insert tuple into catalog */
701 CatalogTupleInsert(rel, tup);
702 heap_freetuple(tup);
703
704 ObjectAddressSet(myself, PublicationNamespaceRelationId, psschid);
705
706 /* Add dependency on the publication */
707 ObjectAddressSet(referenced, PublicationRelationId, pubid);
708 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
709
710 /* Add dependency on the schema */
711 ObjectAddressSet(referenced, NamespaceRelationId, schemaid);
712 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
713
714 /* Close the table */
716
717 /*
718 * Invalidate relcache so that publication info is rebuilt. See
719 * publication_add_relation for why we need to consider all the
720 * partitions.
721 */
722 schemaRels = GetSchemaPublicationRelations(schemaid,
724 InvalidatePublicationRels(schemaRels);
725
726 return myself;
727}
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().