PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pg_publication.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pg_publication.c
4 * publication C API manipulation
5 *
6 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 * IDENTIFICATION
10 * src/backend/catalog/pg_publication.c
11 *
12 *-------------------------------------------------------------------------
13 */
14
15#include "postgres.h"
16
17#include "access/genam.h"
18#include "access/heapam.h"
19#include "access/htup_details.h"
20#include "access/tableam.h"
21#include "catalog/catalog.h"
22#include "catalog/dependency.h"
23#include "catalog/indexing.h"
24#include "catalog/namespace.h"
26#include "catalog/partition.h"
27#include "catalog/pg_inherits.h"
32#include "catalog/pg_type.h"
34#include "funcapi.h"
35#include "utils/array.h"
36#include "utils/builtins.h"
37#include "utils/catcache.h"
38#include "utils/fmgroids.h"
39#include "utils/lsyscache.h"
40#include "utils/rel.h"
41#include "utils/syscache.h"
42
43/* Records association between publication and published table */
44typedef struct
45{
46 Oid relid; /* OID of published table */
47 Oid pubid; /* OID of publication that publishes this
48 * table. */
50
51/*
52 * Check if relation can be in given publication and throws appropriate
53 * error if not.
54 */
55static void
57{
58 Relation targetrel = pri->relation;
59 const char *relname;
60 const char *errormsg;
61
62 if (pri->except)
63 {
65 errormsg = gettext_noop("cannot specify relation \"%s\" in the publication EXCEPT clause");
66 }
67 else
68 {
70 errormsg = gettext_noop("cannot add relation \"%s\" to publication");
71 }
72
73 /* If in EXCEPT clause, must be root partitioned table */
74 if (pri->except && targetrel->rd_rel->relispartition)
77 errmsg(errormsg, relname),
78 errdetail("This operation is not supported for individual partitions.")));
79
80 /* Must be a regular or partitioned table */
85 errmsg(errormsg, relname),
87
88 /* Can't be system table */
92 errmsg(errormsg, relname),
93 errdetail("This operation is not supported for system tables.")));
94
95 /* Can't be conflict log table */
99 errmsg(errormsg, relname),
100 errdetail("This operation is not supported for conflict log tables.")));
101
102 /* UNLOGGED and TEMP relations cannot be part of publication. */
103 if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
106 errmsg(errormsg, relname),
107 errdetail("This operation is not supported for temporary tables.")));
108 else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
111 errmsg(errormsg, relname),
112 errdetail("This operation is not supported for unlogged tables.")));
113}
114
115/*
116 * Check if schema can be in given publication and throw appropriate error if
117 * not.
118 */
119static void
121{
122 /* Can't be system namespace */
127 errmsg("cannot add schema \"%s\" to publication",
129 errdetail("This operation is not supported for system schemas.")));
130
131 /* Can't be temporary namespace */
135 errmsg("cannot add schema \"%s\" to publication",
137 errdetail("Temporary schemas cannot be replicated.")));
138}
139
140/*
141 * Returns if relation represented by oid and Form_pg_class entry
142 * is publishable.
143 *
144 * Does same checks as check_publication_add_relation() above except for
145 * RELKIND_SEQUENCE, but does not need relation to be opened and also does
146 * not throw errors. Here, the additional check is to support ALL SEQUENCES
147 * publication.
148 *
149 * XXX This also excludes all tables with relid < FirstNormalObjectId,
150 * ie all tables created during initdb. This mainly affects the preinstalled
151 * information_schema. IsCatalogRelationOid() only excludes tables with
152 * relid < FirstUnpinnedObjectId, making that test rather redundant,
153 * but really we should get rid of the FirstNormalObjectId test not
154 * IsCatalogRelationOid. We can't do so today because we don't want
155 * information_schema tables to be considered publishable; but this test
156 * is really inadequate for that, since the information_schema could be
157 * dropped and reloaded and then it'll be considered publishable. The best
158 * long-term solution may be to add a "relispublishable" bool to pg_class,
159 * and depend on that instead of OID checks. IsConflictLogTableClass()
160 * excludes tables in conflict schema.
161 */
162static bool
164{
165 return (reltuple->relkind == RELKIND_RELATION ||
167 reltuple->relkind == RELKIND_SEQUENCE) &&
168 !IsCatalogRelationOid(relid) &&
170 reltuple->relpersistence == RELPERSISTENCE_PERMANENT &&
171 relid >= FirstNormalObjectId;
172}
173
174/*
175 * Another variant of is_publishable_class(), taking a Relation.
176 */
177bool
182
183/*
184 * Similar to is_publishable_class() but checks whether the given OID
185 * is a publishable "table" or not.
186 */
187static bool
189{
190 HeapTuple tuple;
192
193 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(tableoid));
194 if (!HeapTupleIsValid(tuple))
195 return false;
196
198
199 /*
200 * is_publishable_class() includes sequences, so we need to explicitly
201 * check the relkind to filter them out here.
202 */
203 if (relform->relkind != RELKIND_SEQUENCE &&
204 is_publishable_class(tableoid, relform))
205 {
206 ReleaseSysCache(tuple);
207 return true;
208 }
209
210 ReleaseSysCache(tuple);
211 return false;
212}
213
214/*
215 * SQL-callable variant of the above
216 *
217 * This returns null when the relation does not exist. This is intended to be
218 * used for example in psql to avoid gratuitous errors when there are
219 * concurrent catalog changes.
220 */
221Datum
223{
224 Oid relid = PG_GETARG_OID(0);
225 HeapTuple tuple;
226 bool result;
227
228 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
229 if (!HeapTupleIsValid(tuple))
232 ReleaseSysCache(tuple);
234}
235
236/*
237 * Returns true if the ancestor is in the list of published relations.
238 * Otherwise, returns false.
239 */
240static bool
242{
243 ListCell *lc;
244
245 foreach(lc, table_infos)
246 {
247 Oid relid = ((published_rel *) lfirst(lc))->relid;
248
249 if (relid == ancestor)
250 return true;
251 }
252
253 return false;
254}
255
256/*
257 * Filter out the partitions whose parent tables are also present in the list.
258 */
259static void
261{
262 ListCell *lc;
263
264 foreach(lc, table_infos)
265 {
266 bool skip = false;
267 List *ancestors = NIL;
268 ListCell *lc2;
270
272 ancestors = get_partition_ancestors(table_info->relid);
273
274 foreach(lc2, ancestors)
275 {
277
279 {
280 skip = true;
281 break;
282 }
283 }
284
285 if (skip)
287 }
288}
289
290/*
291 * Returns true if any schema is associated with the publication, false if no
292 * schema is associated with the publication.
293 */
294bool
320
321/*
322 * Returns true if the publication has explicitly included relation (i.e.,
323 * not marked as EXCEPT).
324 */
325bool
327{
330 SysScanDesc scan;
332 bool result = false;
333
338 ObjectIdGetDatum(pubid));
339
342 true, NULL, 1, &scankey);
343 tup = systable_getnext(scan);
345 {
347
349
350 /*
351 * For any publication, pg_publication_rel contains either only EXCEPT
352 * entries or only explicitly included tables. Therefore, examining
353 * the first tuple is sufficient to determine table inclusion.
354 */
355 result = !pubrel->prexcept;
356 }
357
358 systable_endscan(scan);
360
361 return result;
362}
363
364/*
365 * Returns true if the relation has column list associated with the
366 * publication, false otherwise.
367 *
368 * If a column list is found, the corresponding bitmap is returned through the
369 * cols parameter, if provided. The bitmap is constructed within the given
370 * memory context (mcxt).
371 */
372bool
374 Bitmapset **cols)
375{
377 bool found = false;
378
379 if (pub->alltables)
380 return false;
381
383 ObjectIdGetDatum(relid),
384 ObjectIdGetDatum(pub->oid));
386 {
388 bool isnull;
389
390 /* Lookup the column list attribute. */
393
394 /* Was a column list found? */
395 if (!isnull)
396 {
397 /* Build the column list bitmap in the given memory context. */
398 if (cols)
399 *cols = pub_collist_to_bitmapset(*cols, cfdatum, mcxt);
400
401 found = true;
402 }
403
405 }
406
407 return found;
408}
409
410/*
411 * Gets the relations based on the publication partition option for a specified
412 * relation.
413 */
414List *
416 Oid relid)
417{
420 {
422 NULL);
423
427 {
428 ListCell *lc;
429
430 foreach(lc, all_parts)
431 {
433
436 }
437 }
438 else
439 Assert(false);
440 }
441 else
442 result = lappend_oid(result, relid);
443
444 return result;
445}
446
447/*
448 * Returns the relid of the topmost ancestor that is published via this
449 * publication if any and set its ancestor level to ancestor_level,
450 * otherwise returns InvalidOid.
451 *
452 * The ancestor_level value allows us to compare the results for multiple
453 * publications, and decide which value is higher up.
454 *
455 * Note that the list of ancestors should be ordered such that the topmost
456 * ancestor is at the end of the list.
457 */
458Oid
460{
461 ListCell *lc;
463 int level = 0;
464
465 /*
466 * Find the "topmost" ancestor that is in this publication.
467 */
468 foreach(lc, ancestors)
469 {
473
474 level++;
475
477 {
479
480 if (ancestor_level)
481 *ancestor_level = level;
482 }
483 else
484 {
487 {
489
490 if (ancestor_level)
491 *ancestor_level = level;
492 }
493 }
494
497 }
498
499 return topmost_relid;
500}
501
502/*
503 * attnumstoint2vector
504 * Convert a Bitmapset of AttrNumbers into an int2vector.
505 *
506 * AttrNumber numbers are 0-based, i.e., not offset by
507 * FirstLowInvalidHeapAttributeNumber.
508 */
509static int2vector *
511{
513 int n = bms_num_members(attrs);
514 int i = -1;
515 int j = 0;
516
518
519 while ((i = bms_next_member(attrs, i)) >= 0)
520 {
522
523 result->values[j++] = (int16) i;
524 }
525
526 return result;
527}
528
529/*
530 * Insert new publication / relation mapping.
531 */
534 bool if_not_exists, AlterPublicationStmt *alter_stmt)
535{
536 Relation rel;
539 bool nulls[Natts_pg_publication_rel];
540 Relation targetrel = pri->relation;
543 Bitmapset *attnums;
544 Publication *pub = GetPublication(pubid);
547 List *relids = NIL;
548 int i;
550
552
553 /*
554 * Check for duplicates. Note that this does not really prevent
555 * duplicates, it's here just to provide nicer error message in common
556 * case. The real protection is the unique key on the catalog.
557 */
559 ObjectIdGetDatum(pubid)))
560 {
562
563 if (if_not_exists)
565
568 errmsg("relation \"%s\" is already member of publication \"%s\"",
570 }
571
573
574 /* Validate and translate column names into a Bitmapset of attnums. */
575 attnums = pub_collist_validate(pri->relation, pri->columns);
576
577 /* Form a tuple. */
578 memset(values, 0, sizeof(values));
579 memset(nulls, false, sizeof(nulls));
580
585 ObjectIdGetDatum(pubid);
587 ObjectIdGetDatum(relid);
589 BoolGetDatum(pri->except);
590
591 /* Add qualifications, if available */
592 if (pri->whereClause != NULL)
594 else
595 nulls[Anum_pg_publication_rel_prqual - 1] = true;
596
597 /* Add column list, if available */
598 if (pri->columns)
600 else
601 nulls[Anum_pg_publication_rel_prattrs - 1] = true;
602
604
605 /* Insert tuple into catalog. */
608
609 /* Register dependencies as needed */
611
612 /* Add dependency on the publication */
615
616 /* Add dependency on the relation */
619
620 /* Add dependency on the objects mentioned in the qualifications */
621 if (pri->whereClause)
622 recordDependencyOnSingleRelExpr(&myself, pri->whereClause, relid,
624 false);
625
626 /* Add dependency on the columns, if any are listed */
627 i = -1;
628 while ((i = bms_next_member(attnums, i)) >= 0)
629 {
632 }
633
634 /* Close the table. */
636
637 /*
638 * Determine whether EXCEPT tables require explicit relcache invalidation.
639 *
640 * For CREATE PUBLICATION with EXCEPT tables, invalidation is skipped
641 * here, as CreatePublication() function invalidates all relations as part
642 * of defining a FOR ALL TABLES publication.
643 *
644 * For ALTER PUBLICATION, invalidation is needed only when adding an
645 * EXCEPT table to a publication already marked as ALL TABLES. For
646 * publications that were originally empty or defined as ALL SEQUENCES and
647 * are being converted to ALL TABLES, invalidation is skipped here, as
648 * AlterPublicationAllFlags() function invalidates all relations while
649 * marking the publication as ALL TABLES publication.
650 */
652 (alter_stmt->for_all_tables && pri->except);
653
654 if (!pri->except || inval_except_table)
655 {
656 /*
657 * Invalidate relcache so that publication info is rebuilt.
658 *
659 * For the partitioned tables, we must invalidate all partitions
660 * contained in the respective partition hierarchies, not just the one
661 * explicitly mentioned in the publication. This is required because
662 * we implicitly publish the child tables when the parent table is
663 * published.
664 */
666 relid);
667
669 }
670
671 return myself;
672}
673
674/*
675 * pub_collist_validate
676 * Process and validate the 'columns' list and ensure the columns are all
677 * valid to use for a publication. Checks for and raises an ERROR for
678 * any unknown columns, system columns, duplicate columns, or virtual
679 * generated columns.
680 *
681 * Looks up each column's attnum and returns a 0-based Bitmapset of the
682 * corresponding attnums.
683 */
684Bitmapset *
686{
687 Bitmapset *set = NULL;
688 ListCell *lc;
690
691 foreach(lc, columns)
692 {
693 char *colname = strVal(lfirst(lc));
695
699 errmsg("column \"%s\" of relation \"%s\" does not exist",
701
705 errmsg("cannot use system column \"%s\" in publication column list",
706 colname));
707
708 if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
711 errmsg("cannot use virtual generated column \"%s\" in publication column list",
712 colname));
713
714 if (bms_is_member(attnum, set))
717 errmsg("duplicate column \"%s\" in publication column list",
718 colname));
719
720 set = bms_add_member(set, attnum);
721 }
722
723 return set;
724}
725
726/*
727 * Transform a column list (represented by an array Datum) to a bitmapset.
728 *
729 * If columns isn't NULL, add the column numbers to that set.
730 *
731 * If mcxt isn't NULL, build the bitmapset in that context.
732 */
733Bitmapset *
735{
736 Bitmapset *result = columns;
737 ArrayType *arr;
738 int nelems;
739 int16 *elems;
741
743 nelems = ARR_DIMS(arr)[0];
744 elems = (int16 *) ARR_DATA_PTR(arr);
745
746 /* If a memory context was specified, switch to it. */
747 if (mcxt)
749
750 for (int i = 0; i < nelems; i++)
751 result = bms_add_member(result, elems[i]);
752
753 if (mcxt)
755
756 return result;
757}
758
759/*
760 * Returns a bitmap representing the columns of the specified table.
761 *
762 * Generated columns are included if include_gencols_type is
763 * PUBLISH_GENCOLS_STORED.
764 */
765Bitmapset *
766pub_form_cols_map(Relation relation, PublishGencolsType include_gencols_type)
767{
769 TupleDesc desc = RelationGetDescr(relation);
770
771 for (int i = 0; i < desc->natts; i++)
772 {
773 Form_pg_attribute att = TupleDescAttr(desc, i);
774
775 if (att->attisdropped)
776 continue;
777
778 if (att->attgenerated)
779 {
780 /* We only support replication of STORED generated cols. */
781 if (att->attgenerated != ATTRIBUTE_GENERATED_STORED)
782 continue;
783
784 /* User hasn't requested to replicate STORED generated cols. */
785 if (include_gencols_type != PUBLISH_GENCOLS_STORED)
786 continue;
787 }
788
789 result = bms_add_member(result, att->attnum);
790 }
791
792 return result;
793}
794
795/*
796 * Insert new publication / schema mapping.
797 */
799publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists)
800{
801 Relation rel;
805 Oid psschid;
806 Publication *pub = GetPublication(pubid);
810
812
813 /*
814 * Check for duplicates. Note that this does not really prevent
815 * duplicates, it's here just to provide nicer error message in common
816 * case. The real protection is the unique key on the catalog.
817 */
820 ObjectIdGetDatum(pubid)))
821 {
823
824 if (if_not_exists)
826
829 errmsg("schema \"%s\" is already member of publication \"%s\"",
831 }
832
834
835 /* Form a tuple */
836 memset(values, 0, sizeof(values));
837 memset(nulls, false, sizeof(nulls));
838
843 ObjectIdGetDatum(pubid);
846
848
849 /* Insert tuple into catalog */
852
854
855 /* Add dependency on the publication */
858
859 /* Add dependency on the schema */
862
863 /* Close the table */
865
866 /*
867 * Invalidate relcache so that publication info is rebuilt. See
868 * publication_add_relation for why we need to consider all the
869 * partitions.
870 */
874
875 return myself;
876}
877
878/*
879 * Internal function to get the list of publication oids for a relation.
880 *
881 * If except_flag is true, returns the list of publication that specified the
882 * relation in the EXCEPT clause; otherwise, returns the list of publications
883 * in which relation is included.
884 */
885static List *
887{
888 List *result = NIL;
890
891 /* Find all publications associated with the relation. */
893 ObjectIdGetDatum(relid));
894 for (int i = 0; i < pubrellist->n_members; i++)
895 {
896 HeapTuple tup = &pubrellist->members[i]->tuple;
898 Oid pubid = pubrel->prpubid;
899
900 if (pubrel->prexcept == except_flag)
901 result = lappend_oid(result, pubid);
902 }
903
905
906 return result;
907}
908
909/*
910 * Gets list of publication oids for a relation.
911 */
912List *
914{
915 return get_relation_publications(relid, false);
916}
917
918/*
919 * Gets list of publication oids which has relation in the EXCEPT clause.
920 */
921List *
923{
924 return get_relation_publications(relid, true);
925}
926
927/*
928 * Internal function to get the list of relation oids for a publication.
929 *
930 * If except_flag is true, returns the list of relations specified in the
931 * EXCEPT clause of the publication; otherwise, returns the list of relations
932 * included in the publication.
933 */
934static List *
936 bool except_flag)
937{
938 List *result;
941 SysScanDesc scan;
943
944 /* Find all relations associated with the publication. */
946
950 ObjectIdGetDatum(pubid));
951
953 true, NULL, 1, &scankey);
954
955 result = NIL;
956 while (HeapTupleIsValid(tup = systable_getnext(scan)))
957 {
959
961
962 if (except_flag == pubrel->prexcept)
964 pubrel->prrelid);
965 }
966
967 systable_endscan(scan);
969
970 /* Now sort and de-duplicate the result list */
973
974 return result;
975}
976
977/*
978 * Gets list of relation oids that are associated with a publication.
979 *
980 * This should only be used FOR TABLE publications, the FOR ALL TABLES/SEQUENCES
981 * should use GetAllPublicationRelations().
982 */
983List *
985{
986 Assert(!GetPublication(pubid)->alltables);
987
988 return get_publication_relations(pubid, pub_partopt, false);
989}
990
991/*
992 * Gets list of table oids that were specified in the EXCEPT clause for a
993 * publication.
994 *
995 * This should only be used FOR ALL TABLES publications.
996 */
997List *
999{
1000 Assert(GetPublication(pubid)->alltables);
1001
1002 return get_publication_relations(pubid, pub_partopt, true);
1003}
1004
1005/*
1006 * Gets list of publication oids for publications marked as FOR ALL TABLES.
1007 */
1008List *
1010{
1011 List *result;
1012 Relation rel;
1014 SysScanDesc scan;
1015 HeapTuple tup;
1016
1017 /* Find all publications that are marked as for all tables. */
1019
1023 BoolGetDatum(true));
1024
1025 scan = systable_beginscan(rel, InvalidOid, false,
1026 NULL, 1, &scankey);
1027
1028 result = NIL;
1029 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1030 {
1031 Oid oid = ((Form_pg_publication) GETSTRUCT(tup))->oid;
1032
1033 result = lappend_oid(result, oid);
1034 }
1035
1036 systable_endscan(scan);
1038
1039 return result;
1040}
1041
1042/*
1043 * Gets list of all relations published by FOR ALL TABLES/SEQUENCES
1044 * publication.
1045 *
1046 * If the publication publishes partition changes via their respective root
1047 * partitioned tables, we must exclude partitions in favor of including the
1048 * root partitioned tables. This is not applicable to FOR ALL SEQUENCES
1049 * publication.
1050 *
1051 * For a FOR ALL TABLES publication, the returned list excludes tables mentioned
1052 * in the EXCEPT clause.
1053 */
1054List *
1055GetAllPublicationRelations(Oid pubid, char relkind, bool pubviaroot)
1056{
1058 ScanKeyData key[1];
1059 TableScanDesc scan;
1060 HeapTuple tuple;
1061 List *result = NIL;
1062 List *exceptlist = NIL;
1063
1064 Assert(!(relkind == RELKIND_SEQUENCE && pubviaroot));
1065
1066 /* EXCEPT filtering applies only to relations, not sequences */
1067 if (relkind == RELKIND_RELATION)
1068 exceptlist = GetExcludedPublicationTables(pubid, pubviaroot ?
1071
1073
1074 ScanKeyInit(&key[0],
1077 CharGetDatum(relkind));
1078
1079 scan = table_beginscan_catalog(classRel, 1, key);
1080
1081 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1082 {
1084 Oid relid = relForm->oid;
1085
1086 if (is_publishable_class(relid, relForm) &&
1087 !(relForm->relispartition && pubviaroot) &&
1088 !list_member_oid(exceptlist, relid))
1089 result = lappend_oid(result, relid);
1090 }
1091
1092 table_endscan(scan);
1093
1094 if (pubviaroot)
1095 {
1096 ScanKeyInit(&key[0],
1100
1101 scan = table_beginscan_catalog(classRel, 1, key);
1102
1103 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1104 {
1106 Oid relid = relForm->oid;
1107
1108 if (is_publishable_class(relid, relForm) &&
1109 !relForm->relispartition &&
1110 !list_member_oid(exceptlist, relid))
1111 result = lappend_oid(result, relid);
1112 }
1113
1114 table_endscan(scan);
1115 }
1116
1118 return result;
1119}
1120
1121/*
1122 * Gets the list of schema oids for a publication.
1123 *
1124 * This should only be used FOR TABLES IN SCHEMA publications.
1125 */
1126List *
1128{
1129 List *result = NIL;
1132 SysScanDesc scan;
1133 HeapTuple tup;
1134
1135 /* Find all schemas associated with the publication */
1137
1141 ObjectIdGetDatum(pubid));
1142
1145 true, NULL, 1, &scankey);
1146 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1147 {
1149
1151
1152 result = lappend_oid(result, pubsch->pnnspid);
1153 }
1154
1155 systable_endscan(scan);
1157
1158 return result;
1159}
1160
1161/*
1162 * Gets the list of publication oids associated with a specified schema.
1163 */
1164List *
1166{
1167 List *result = NIL;
1169 int i;
1170
1171 /* Find all publications associated with the schema */
1174 for (i = 0; i < pubschlist->n_members; i++)
1175 {
1176 HeapTuple tup = &pubschlist->members[i]->tuple;
1178
1179 result = lappend_oid(result, pubid);
1180 }
1181
1183
1184 return result;
1185}
1186
1187/*
1188 * Get the list of publishable relation oids for a specified schema.
1189 */
1190List *
1192{
1194 ScanKeyData key[1];
1195 TableScanDesc scan;
1196 HeapTuple tuple;
1197 List *result = NIL;
1198
1200
1202
1203 ScanKeyInit(&key[0],
1207
1208 /* get all the relations present in the specified schema */
1209 scan = table_beginscan_catalog(classRel, 1, key);
1210 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1211 {
1213 Oid relid = relForm->oid;
1214 char relkind;
1215
1216 if (!is_publishable_class(relid, relForm))
1217 continue;
1218
1219 relkind = get_rel_relkind(relid);
1220 if (relkind == RELKIND_RELATION)
1221 result = lappend_oid(result, relid);
1222 else if (relkind == RELKIND_PARTITIONED_TABLE)
1223 {
1225
1226 /*
1227 * It is quite possible that some of the partitions are in a
1228 * different schema than the parent table, so we need to get such
1229 * partitions separately.
1230 */
1233 relForm->oid);
1235 }
1236 }
1237
1238 table_endscan(scan);
1240 return result;
1241}
1242
1243/*
1244 * Gets the list of all relations published by FOR TABLES IN SCHEMA
1245 * publication.
1246 */
1247List *
1249{
1250 List *result = NIL;
1252 ListCell *cell;
1253
1254 foreach(cell, pubschemalist)
1255 {
1256 Oid schemaid = lfirst_oid(cell);
1257 List *schemaRels = NIL;
1258
1261 }
1262
1263 return result;
1264}
1265
1266/*
1267 * Get publication using oid
1268 *
1269 * The Publication struct and its data are palloc'ed here.
1270 */
1273{
1274 HeapTuple tup;
1275 Publication *pub;
1277
1279 if (!HeapTupleIsValid(tup))
1280 elog(ERROR, "cache lookup failed for publication %u", pubid);
1281
1283
1285 pub->oid = pubid;
1286 pub->name = pstrdup(NameStr(pubform->pubname));
1287 pub->alltables = pubform->puballtables;
1288 pub->allsequences = pubform->puballsequences;
1289 pub->pubactions.pubinsert = pubform->pubinsert;
1290 pub->pubactions.pubupdate = pubform->pubupdate;
1291 pub->pubactions.pubdelete = pubform->pubdelete;
1292 pub->pubactions.pubtruncate = pubform->pubtruncate;
1293 pub->pubviaroot = pubform->pubviaroot;
1294 pub->pubgencols_type = pubform->pubgencols;
1295
1297
1298 return pub;
1299}
1300
1301/*
1302 * Get Publication using name.
1303 */
1305GetPublicationByName(const char *pubname, bool missing_ok)
1306{
1307 Oid oid;
1308
1309 oid = get_publication_oid(pubname, missing_ok);
1310
1311 return OidIsValid(oid) ? GetPublication(oid) : NULL;
1312}
1313
1314/*
1315 * A helper function for pg_get_publication_tables() to check whether the
1316 * table with the given relid is published in the specified publication.
1317 *
1318 * This function evaluates the effective published OID based on the
1319 * publish_via_partition_root setting, rather than just checking catalog entries
1320 * (e.g., pg_publication_rel). For instance, when publish_via_partition_root is
1321 * false, it returns false for a parent partitioned table and returns true
1322 * for its leaf partitions, even if the parent is the one explicitly added
1323 * to the publication.
1324 *
1325 * For performance reasons, this function avoids the overhead of constructing
1326 * the complete list of published tables during the evaluation. It can execute
1327 * quickly even when the publication contains a large number of relations.
1328 *
1329 * Note: this leaks memory for the ancestors list into the current memory
1330 * context.
1331 */
1332static bool
1334{
1335 bool relispartition;
1336 List *ancestors = NIL;
1337
1338 /*
1339 * For non-pubviaroot publications, a partitioned table is never the
1340 * effective published OID; only its leaf partitions can be.
1341 */
1343 return false;
1344
1346
1347 if (relispartition)
1348 ancestors = get_partition_ancestors(relid);
1349
1350 if (pub->alltables)
1351 {
1352 /*
1353 * ALL TABLES with pubviaroot includes only regular tables or top-most
1354 * partitioned tables -- never child partitions.
1355 */
1356 if (pub->pubviaroot && relispartition)
1357 return false;
1358
1359 /*
1360 * For ALL TABLES publications, the table is published unless it
1361 * appears in the EXCEPT clause. Only the top-most can appear in the
1362 * EXCEPT clause, so exclusion must be evaluated at the top-most
1363 * ancestor if it has. These publications store only EXCEPT'ed tables
1364 * in pg_publication_rel, so checking existence is sufficient.
1365 *
1366 * Note that this existence check below would incorrectly return true
1367 * (published) for partitions when pubviaroot is enabled; however,
1368 * that case is already caught and returned false by the above check.
1369 */
1371 ObjectIdGetDatum(ancestors
1372 ? llast_oid(ancestors) : relid),
1373 ObjectIdGetDatum(pub->oid));
1374 }
1375
1376 /*
1377 * Non-ALL-TABLE publication cases.
1378 *
1379 * A table is published if it (or a containing schema) was explicitly
1380 * added, or if it is a partition whose ancestor was added.
1381 */
1382
1383 /*
1384 * If an ancestor is published, the partition's status depends on
1385 * publish_via_partition_root value.
1386 *
1387 * If it's true, the ancestor's relation OID is the effective published
1388 * OID, so the partition itself should be excluded (return false).
1389 *
1390 * If it's false, the partition is covered by its ancestor's presence in
1391 * the publication, it should be included (return true).
1392 */
1393 if (relispartition &&
1395 return !pub->pubviaroot;
1396
1397 /*
1398 * Check whether the table is explicitly published via pg_publication_rel
1399 * or pg_publication_namespace.
1400 */
1402 ObjectIdGetDatum(relid),
1403 ObjectIdGetDatum(pub->oid)) ||
1406 ObjectIdGetDatum(pub->oid)));
1407}
1408
1409/*
1410 * Helper function to get information of the tables in the given
1411 * publication(s).
1412 *
1413 * If filter_by_relid is true, only the row(s) for target_relid is returned;
1414 * if target_relid does not exist or is not part of the publications, zero
1415 * rows are returned. If filter_by_relid is false, rows for all tables
1416 * within the specified publications are returned and target_relid is
1417 * ignored.
1418 *
1419 * Returns pubid, relid, column list, and row filter for each table.
1420 */
1421static Datum
1424 bool pub_missing_ok)
1425{
1426#define NUM_PUBLICATION_TABLES_ELEM 4
1428 List *table_infos = NIL;
1429
1430 /* stuff done only on the first call of the function */
1431 if (SRF_IS_FIRSTCALL())
1432 {
1433 TupleDesc tupdesc;
1434 MemoryContext oldcontext;
1435 Datum *elems;
1436 int nelems,
1437 i;
1438 bool viaroot = false;
1439
1440 /* create a function context for cross-call persistence */
1442
1443 /*
1444 * Preliminary check if the specified table can be published in the
1445 * first place. If not, we can return early without checking the given
1446 * publications and the table.
1447 */
1450
1451 /* switch to memory context appropriate for multiple function calls */
1452 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1453
1454 /*
1455 * Deconstruct the parameter into elements where each element is a
1456 * publication name.
1457 */
1458 deconstruct_array_builtin(pubnames, TEXTOID, &elems, NULL, &nelems);
1459
1460 /* Get Oids of tables from each publication. */
1461 for (i = 0; i < nelems; i++)
1462 {
1465 ListCell *lc;
1466
1469
1470 if (pub_elem == NULL)
1471 continue;
1472
1473 if (filter_by_relid)
1474 {
1475 /* Check if the given table is published for the publication */
1477 {
1479 }
1480 }
1481 else
1482 {
1483 /*
1484 * Publications support partitioned tables. If
1485 * publish_via_partition_root is false, all changes are
1486 * replicated using leaf partition identity and schema, so we
1487 * only need those. Otherwise, get the partitioned table
1488 * itself.
1489 */
1490 if (pub_elem->alltables)
1493 pub_elem->pubviaroot);
1494 else
1495 {
1496 List *relids,
1497 *schemarelids;
1498
1500 pub_elem->pubviaroot ?
1504 pub_elem->pubviaroot ?
1508 }
1509 }
1510
1511 /*
1512 * Record the published table and the corresponding publication so
1513 * that we can get row filters and column lists later.
1514 *
1515 * When a table is published by multiple publications, to obtain
1516 * all row filters and column lists, the structure related to this
1517 * table will be recorded multiple times.
1518 */
1519 foreach(lc, pub_elem_tables)
1520 {
1522
1523 table_info->relid = lfirst_oid(lc);
1524 table_info->pubid = pub_elem->oid;
1526 }
1527
1528 /* At least one publication is using publish_via_partition_root. */
1529 if (pub_elem->pubviaroot)
1530 viaroot = true;
1531 }
1532
1533 /*
1534 * If the publication publishes partition changes via their respective
1535 * root partitioned tables, we must exclude partitions in favor of
1536 * including the root partitioned tables. Otherwise, the function
1537 * could return both the child and parent tables which could cause
1538 * data of the child table to be double-published on the subscriber
1539 * side.
1540 */
1541 if (viaroot)
1543
1544 /* Construct a tuple descriptor for the result rows. */
1546 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "pubid",
1547 OIDOID, -1, 0);
1548 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "relid",
1549 OIDOID, -1, 0);
1550 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "attrs",
1551 INT2VECTOROID, -1, 0);
1552 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "qual",
1553 PG_NODE_TREEOID, -1, 0);
1554
1555 TupleDescFinalize(tupdesc);
1556 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
1557 funcctx->user_fctx = table_infos;
1558
1559 MemoryContextSwitchTo(oldcontext);
1560 }
1561
1562 /* stuff done on every call of the function */
1564 table_infos = (List *) funcctx->user_fctx;
1565
1566 if (funcctx->call_cntr < list_length(table_infos))
1567 {
1570 Publication *pub;
1572 Oid relid = table_info->relid;
1575 bool nulls[NUM_PUBLICATION_TABLES_ELEM] = {0};
1576
1577 /*
1578 * Form tuple with appropriate data.
1579 */
1580
1581 pub = GetPublication(table_info->pubid);
1582
1583 values[0] = ObjectIdGetDatum(pub->oid);
1584 values[1] = ObjectIdGetDatum(relid);
1585
1586 /*
1587 * We don't consider row filters or column lists for FOR ALL TABLES or
1588 * FOR TABLES IN SCHEMA publications.
1589 */
1590 if (!pub->alltables &&
1593 ObjectIdGetDatum(pub->oid)))
1595 ObjectIdGetDatum(relid),
1596 ObjectIdGetDatum(pub->oid));
1597
1599 {
1600 /* Lookup the column list attribute. */
1603 &(nulls[2]));
1604
1605 /* Null indicates no filter. */
1608 &(nulls[3]));
1609 }
1610 else
1611 {
1612 nulls[2] = true;
1613 nulls[3] = true;
1614 }
1615
1616 /* Show all columns when the column list is not specified. */
1617 if (nulls[2])
1618 {
1619 Relation rel = table_open(relid, AccessShareLock);
1620 int nattnums = 0;
1621 int16 *attnums;
1622 TupleDesc desc = RelationGetDescr(rel);
1623 int i;
1624
1625 attnums = palloc_array(int16, desc->natts);
1626
1627 for (i = 0; i < desc->natts; i++)
1628 {
1629 Form_pg_attribute att = TupleDescAttr(desc, i);
1630
1631 if (att->attisdropped)
1632 continue;
1633
1634 if (att->attgenerated)
1635 {
1636 /* We only support replication of STORED generated cols. */
1637 if (att->attgenerated != ATTRIBUTE_GENERATED_STORED)
1638 continue;
1639
1640 /*
1641 * User hasn't requested to replicate STORED generated
1642 * cols.
1643 */
1645 continue;
1646 }
1647
1648 attnums[nattnums++] = att->attnum;
1649 }
1650
1651 if (nattnums > 0)
1652 {
1653 values[2] = PointerGetDatum(buildint2vector(attnums, nattnums));
1654 nulls[2] = false;
1655 }
1656
1658 }
1659
1660 rettuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
1661
1663 }
1664
1666}
1667
1668Datum
1670{
1671 /*
1672 * Get information for all tables in the given publications.
1673 * filter_by_relid is false so all tables are returned; pub_missing_ok is
1674 * false for backward compatibility.
1675 */
1677 InvalidOid, false, false);
1678}
1679
1680Datum
1682{
1683 /*
1684 * Get information for the specified table in the given publications. The
1685 * SQL-level function is declared STRICT, so target_relid is guaranteed to
1686 * be non-NULL here.
1687 */
1689 PG_GETARG_OID(1), true, true);
1690}
1691
1692/*
1693 * Returns Oids of sequences in a publication.
1694 */
1695Datum
1697{
1699 List *sequences = NIL;
1700
1701 /* stuff done only on the first call of the function */
1702 if (SRF_IS_FIRSTCALL())
1703 {
1704 char *pubname = text_to_cstring(PG_GETARG_TEXT_PP(0));
1705 Publication *publication;
1706 MemoryContext oldcontext;
1707
1708 /* create a function context for cross-call persistence */
1710
1711 /* switch to memory context appropriate for multiple function calls */
1712 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1713
1714 publication = GetPublicationByName(pubname, false);
1715
1716 if (publication->allsequences)
1719 false);
1720
1721 funcctx->user_fctx = sequences;
1722
1723 MemoryContextSwitchTo(oldcontext);
1724 }
1725
1726 /* stuff done on every call of the function */
1728 sequences = (List *) funcctx->user_fctx;
1729
1730 if (funcctx->call_cntr < list_length(sequences))
1731 {
1732 Oid relid = list_nth_oid(sequences, funcctx->call_cntr);
1733
1735 }
1736
1738}
#define PG_GETARG_ARRAYTYPE_P(n)
Definition array.h:263
#define ARR_DATA_PTR(a)
Definition array.h:322
#define DatumGetArrayTypeP(X)
Definition array.h:261
#define ARR_DIMS(a)
Definition array.h:294
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
int16 AttrNumber
Definition attnum.h:21
#define AttrNumberIsForUserDefinedAttr(attributeNumber)
Definition attnum.h:41
#define InvalidAttrNumber
Definition attnum.h:23
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1425
int bms_num_members(const Bitmapset *a)
Definition bitmapset.c:879
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:645
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:934
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define CStringGetTextDatum(s)
Definition builtins.h:98
#define TextDatumGetCString(d)
Definition builtins.h:99
#define NameStr(name)
Definition c.h:894
#define gettext_noop(x)
Definition c.h:1344
#define Assert(condition)
Definition c.h:1002
int16_t int16
Definition c.h:678
#define PG_INT16_MAX
Definition c.h:729
#define OidIsValid(objectId)
Definition c.h:917
bool IsToastNamespace(Oid namespaceId)
Definition catalog.c:277
bool IsConflictLogTableClass(Form_pg_class reltuple)
Definition catalog.c:242
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition catalog.c:475
bool IsConflictLogTableNamespace(Oid namespaceId)
Definition catalog.c:290
bool IsCatalogNamespace(Oid namespaceId)
Definition catalog.c:259
bool IsCatalogRelation(Relation relation)
Definition catalog.c:106
bool IsCatalogRelationOid(Oid relid)
Definition catalog.c:123
uint32 result
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
@ DEPENDENCY_AUTO
Definition dependency.h:34
@ DEPENDENCY_NORMAL
Definition dependency.h:33
int errcode(int sqlerrcode)
Definition elog.c:875
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
#define palloc_object(type)
Definition fe_memutils.h:89
#define palloc_array(type, count)
Definition fe_memutils.h:91
#define PG_GETARG_OID(n)
Definition fmgr.h:275
#define PG_GETARG_TEXT_PP(n)
Definition fmgr.h:310
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
#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
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition heapam.c:1435
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
int2vector * buildint2vector(const int16 *int2s, int n)
Definition int.c:114
int j
Definition isn.c:78
int i
Definition isn.c:77
List * list_concat_unique_oid(List *list1, const List *list2)
Definition list.c:1469
List * lappend(List *list, void *datum)
Definition list.c:339
void list_sort(List *list, list_sort_comparator cmp)
Definition list.c:1674
List * list_concat(List *list1, const List *list2)
Definition list.c:561
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
void list_deduplicate_oid(List *list)
Definition list.c:1495
int list_oid_cmp(const ListCell *p1, const ListCell *p2)
Definition list.c:1703
void list_free(List *list)
Definition list.c:1546
bool list_member_oid(const List *list, Oid datum)
Definition list.c:722
#define NoLock
Definition lockdefs.h:34
#define AccessShareLock
Definition lockdefs.h:36
#define RowExclusiveLock
Definition lockdefs.h:38
bool get_rel_relispartition(Oid relid)
Definition lsyscache.c:2341
AttrNumber get_attnum(Oid relid, const char *attname)
Definition lsyscache.c:1084
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2317
Oid get_publication_oid(const char *pubname, bool missing_ok)
Definition lsyscache.c:3986
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2266
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3682
char * pstrdup(const char *in)
Definition mcxt.c:1910
bool isAnyTempNamespace(Oid namespaceId)
Definition namespace.c:3759
static char * errmsg
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
char * nodeToString(const void *obj)
Definition outfuncs.c:811
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
List * get_partition_ancestors(Oid relid)
Definition partition.c:134
int16 attnum
FormData_pg_attribute * Form_pg_attribute
static const struct exclude_list_item skip[]
int errdetail_relkind_not_supported(char relkind)
Definition pg_class.c:24
NameData relname
Definition pg_class.h:40
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition pg_depend.c:51
static SequenceItem * sequences
Definition pg_dump.c:214
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
static Oid list_nth_oid(const List *list, int n)
Definition pg_list.h:353
#define foreach_delete_current(lst, var_or_cell)
Definition pg_list.h:423
#define list_make1_oid(x1)
Definition pg_list.h:274
#define llast_oid(l)
Definition pg_list.h:200
static void * list_nth(const List *list, int n)
Definition pg_list.h:331
#define lfirst_oid(lc)
Definition pg_list.h:174
static int2vector * attnumstoint2vector(Bitmapset *attrs)
Bitmapset * pub_collist_validate(Relation targetrel, List *columns)
List * GetPubPartitionOptionRelations(List *result, PublicationPartOpt pub_partopt, Oid relid)
bool is_schema_publication(Oid pubid)
static Datum pg_get_publication_tables(FunctionCallInfo fcinfo, ArrayType *pubnames, Oid target_relid, bool filter_by_relid, bool pub_missing_ok)
ObjectAddress publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists)
List * GetPublicationSchemas(Oid pubid)
static void check_publication_add_relation(PublicationRelInfo *pri)
List * GetAllTablesPublications(void)
List * GetAllSchemaPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
Datum pg_get_publication_tables_a(PG_FUNCTION_ARGS)
List * GetRelationIncludedPublications(Oid relid)
Publication * GetPublicationByName(const char *pubname, bool missing_ok)
List * GetSchemaPublications(Oid schemaid)
static void filter_partitions(List *table_infos)
Oid GetTopMostAncestorInPublication(Oid puboid, List *ancestors, int *ancestor_level)
List * GetSchemaPublicationRelations(Oid schemaid, PublicationPartOpt pub_partopt)
List * GetIncludedPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
static List * get_publication_relations(Oid pubid, PublicationPartOpt pub_partopt, bool except_flag)
static bool is_publishable_class(Oid relid, Form_pg_class reltuple)
ObjectAddress publication_add_relation(Oid pubid, PublicationRelInfo *pri, bool if_not_exists, AlterPublicationStmt *alter_stmt)
Datum pg_get_publication_sequences(PG_FUNCTION_ARGS)
List * GetRelationExcludedPublications(Oid relid)
Bitmapset * pub_form_cols_map(Relation relation, PublishGencolsType include_gencols_type)
Publication * GetPublication(Oid pubid)
static bool is_publishable_table(Oid tableoid)
#define NUM_PUBLICATION_TABLES_ELEM
static bool is_ancestor_member_tableinfos(Oid ancestor, List *table_infos)
bool check_and_fetch_column_list(Publication *pub, Oid relid, MemoryContext mcxt, Bitmapset **cols)
static void check_publication_add_schema(Oid schemaid)
static bool is_table_publishable_in_publication(Oid relid, Publication *pub)
Datum pg_get_publication_tables_b(PG_FUNCTION_ARGS)
List * GetAllPublicationRelations(Oid pubid, char relkind, bool pubviaroot)
Bitmapset * pub_collist_to_bitmapset(Bitmapset *columns, Datum pubcols, MemoryContext mcxt)
bool is_table_publication(Oid pubid)
static List * get_relation_publications(Oid relid, bool except_flag)
Datum pg_relation_is_publishable(PG_FUNCTION_ARGS)
bool is_publishable_relation(Relation rel)
List * GetExcludedPublicationTables(Oid pubid, PublicationPartOpt pub_partopt)
END_CATALOG_STRUCT typedef FormData_pg_publication * Form_pg_publication
PublicationPartOpt
@ PUBLICATION_PART_LEAF
@ PUBLICATION_PART_ROOT
@ PUBLICATION_PART_ALL
END_CATALOG_STRUCT typedef FormData_pg_publication_namespace * Form_pg_publication_namespace
END_CATALOG_STRUCT typedef FormData_pg_publication_rel * Form_pg_publication_rel
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
#define PointerGetDatum(X)
Definition postgres.h:354
static Datum CharGetDatum(char X)
Definition postgres.h:132
#define InvalidOid
unsigned int Oid
static int fb(int x)
void InvalidatePublicationRels(List *relids)
#define RelationGetForm(relation)
Definition rel.h:510
#define RelationGetRelid(relation)
Definition rel.h:516
#define RelationGetDescr(relation)
Definition rel.h:542
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationGetNamespace(relation)
Definition rel.h:557
char * RelationGetQualifiedRelationName(Relation rel)
Definition relcache.c:2144
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
#define ERRCODE_DUPLICATE_OBJECT
Definition streamutil.c:30
Definition pg_list.h:54
PublishGencolsType pubgencols_type
PublicationActions pubactions
Form_pg_class rd_rel
Definition rel.h:111
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache2(SysCacheIdentifier cacheId, Datum key1, Datum key2)
Definition syscache.c:231
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596
#define SearchSysCacheCopy2(cacheId, key1, key2)
Definition syscache.h:93
#define ReleaseSysCacheList(x)
Definition syscache.h:134
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition syscache.h:102
#define SearchSysCacheList1(cacheId, key1)
Definition syscache.h:127
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, ScanKeyData *key)
Definition tableam.c:113
static void table_endscan(TableScanDesc scan)
Definition tableam.h:1061
#define FirstNormalObjectId
Definition transam.h:197
TupleDesc CreateTemplateTupleDesc(int natts)
Definition tupdesc.c:165
void TupleDescFinalize(TupleDesc tupdesc)
Definition tupdesc.c:511
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition tupdesc.c:909
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
#define strVal(v)
Definition value.h:82
char * text_to_cstring(const text *t)
Definition varlena.c:217