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 /* UNLOGGED and TEMP relations cannot be part of publication. */
96 if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
99 errmsg(errormsg, relname),
100 errdetail("This operation is not supported for temporary tables.")));
101 else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
104 errmsg(errormsg, relname),
105 errdetail("This operation is not supported for unlogged tables.")));
106}
107
108/*
109 * Check if schema can be in given publication and throw appropriate error if
110 * not.
111 */
112static void
114{
115 /* Can't be system namespace */
119 errmsg("cannot add schema \"%s\" to publication",
121 errdetail("This operation is not supported for system schemas.")));
122
123 /* Can't be temporary namespace */
127 errmsg("cannot add schema \"%s\" to publication",
129 errdetail("Temporary schemas cannot be replicated.")));
130}
131
132/*
133 * Returns if relation represented by oid and Form_pg_class entry
134 * is publishable.
135 *
136 * Does same checks as check_publication_add_relation() above except for
137 * RELKIND_SEQUENCE, but does not need relation to be opened and also does
138 * not throw errors. Here, the additional check is to support ALL SEQUENCES
139 * publication.
140 *
141 * XXX This also excludes all tables with relid < FirstNormalObjectId,
142 * ie all tables created during initdb. This mainly affects the preinstalled
143 * information_schema. IsCatalogRelationOid() only excludes tables with
144 * relid < FirstUnpinnedObjectId, making that test rather redundant,
145 * but really we should get rid of the FirstNormalObjectId test not
146 * IsCatalogRelationOid. We can't do so today because we don't want
147 * information_schema tables to be considered publishable; but this test
148 * is really inadequate for that, since the information_schema could be
149 * dropped and reloaded and then it'll be considered publishable. The best
150 * long-term solution may be to add a "relispublishable" bool to pg_class,
151 * and depend on that instead of OID checks.
152 */
153static bool
155{
156 return (reltuple->relkind == RELKIND_RELATION ||
158 reltuple->relkind == RELKIND_SEQUENCE) &&
159 !IsCatalogRelationOid(relid) &&
160 reltuple->relpersistence == RELPERSISTENCE_PERMANENT &&
161 relid >= FirstNormalObjectId;
162}
163
164/*
165 * Another variant of is_publishable_class(), taking a Relation.
166 */
167bool
172
173/*
174 * Similar to is_publishable_class() but checks whether the given OID
175 * is a publishable "table" or not.
176 */
177static bool
179{
180 HeapTuple tuple;
182
183 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(tableoid));
184 if (!HeapTupleIsValid(tuple))
185 return false;
186
188
189 /*
190 * is_publishable_class() includes sequences, so we need to explicitly
191 * check the relkind to filter them out here.
192 */
193 if (relform->relkind != RELKIND_SEQUENCE &&
194 is_publishable_class(tableoid, relform))
195 {
196 ReleaseSysCache(tuple);
197 return true;
198 }
199
200 ReleaseSysCache(tuple);
201 return false;
202}
203
204/*
205 * SQL-callable variant of the above
206 *
207 * This returns null when the relation does not exist. This is intended to be
208 * used for example in psql to avoid gratuitous errors when there are
209 * concurrent catalog changes.
210 */
211Datum
213{
214 Oid relid = PG_GETARG_OID(0);
215 HeapTuple tuple;
216 bool result;
217
218 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
219 if (!HeapTupleIsValid(tuple))
222 ReleaseSysCache(tuple);
224}
225
226/*
227 * Returns true if the ancestor is in the list of published relations.
228 * Otherwise, returns false.
229 */
230static bool
232{
233 ListCell *lc;
234
235 foreach(lc, table_infos)
236 {
237 Oid relid = ((published_rel *) lfirst(lc))->relid;
238
239 if (relid == ancestor)
240 return true;
241 }
242
243 return false;
244}
245
246/*
247 * Filter out the partitions whose parent tables are also present in the list.
248 */
249static void
251{
252 ListCell *lc;
253
254 foreach(lc, table_infos)
255 {
256 bool skip = false;
257 List *ancestors = NIL;
258 ListCell *lc2;
260
262 ancestors = get_partition_ancestors(table_info->relid);
263
264 foreach(lc2, ancestors)
265 {
267
269 {
270 skip = true;
271 break;
272 }
273 }
274
275 if (skip)
277 }
278}
279
280/*
281 * Returns true if any schema is associated with the publication, false if no
282 * schema is associated with the publication.
283 */
284bool
310
311/*
312 * Returns true if the publication has explicitly included relation (i.e.,
313 * not marked as EXCEPT).
314 */
315bool
317{
320 SysScanDesc scan;
322 bool result = false;
323
328 ObjectIdGetDatum(pubid));
329
332 true, NULL, 1, &scankey);
333 tup = systable_getnext(scan);
335 {
337
339
340 /*
341 * For any publication, pg_publication_rel contains either only EXCEPT
342 * entries or only explicitly included tables. Therefore, examining
343 * the first tuple is sufficient to determine table inclusion.
344 */
345 result = !pubrel->prexcept;
346 }
347
348 systable_endscan(scan);
350
351 return result;
352}
353
354/*
355 * Returns true if the relation has column list associated with the
356 * publication, false otherwise.
357 *
358 * If a column list is found, the corresponding bitmap is returned through the
359 * cols parameter, if provided. The bitmap is constructed within the given
360 * memory context (mcxt).
361 */
362bool
364 Bitmapset **cols)
365{
367 bool found = false;
368
369 if (pub->alltables)
370 return false;
371
373 ObjectIdGetDatum(relid),
374 ObjectIdGetDatum(pub->oid));
376 {
378 bool isnull;
379
380 /* Lookup the column list attribute. */
383
384 /* Was a column list found? */
385 if (!isnull)
386 {
387 /* Build the column list bitmap in the given memory context. */
388 if (cols)
389 *cols = pub_collist_to_bitmapset(*cols, cfdatum, mcxt);
390
391 found = true;
392 }
393
395 }
396
397 return found;
398}
399
400/*
401 * Gets the relations based on the publication partition option for a specified
402 * relation.
403 */
404List *
406 Oid relid)
407{
410 {
412 NULL);
413
417 {
418 ListCell *lc;
419
420 foreach(lc, all_parts)
421 {
423
426 }
427 }
428 else
429 Assert(false);
430 }
431 else
432 result = lappend_oid(result, relid);
433
434 return result;
435}
436
437/*
438 * Returns the relid of the topmost ancestor that is published via this
439 * publication if any and set its ancestor level to ancestor_level,
440 * otherwise returns InvalidOid.
441 *
442 * The ancestor_level value allows us to compare the results for multiple
443 * publications, and decide which value is higher up.
444 *
445 * Note that the list of ancestors should be ordered such that the topmost
446 * ancestor is at the end of the list.
447 */
448Oid
450{
451 ListCell *lc;
453 int level = 0;
454
455 /*
456 * Find the "topmost" ancestor that is in this publication.
457 */
458 foreach(lc, ancestors)
459 {
463
464 level++;
465
467 {
469
470 if (ancestor_level)
471 *ancestor_level = level;
472 }
473 else
474 {
477 {
479
480 if (ancestor_level)
481 *ancestor_level = level;
482 }
483 }
484
487 }
488
489 return topmost_relid;
490}
491
492/*
493 * attnumstoint2vector
494 * Convert a Bitmapset of AttrNumbers into an int2vector.
495 *
496 * AttrNumber numbers are 0-based, i.e., not offset by
497 * FirstLowInvalidHeapAttributeNumber.
498 */
499static int2vector *
501{
503 int n = bms_num_members(attrs);
504 int i = -1;
505 int j = 0;
506
508
509 while ((i = bms_next_member(attrs, i)) >= 0)
510 {
512
513 result->values[j++] = (int16) i;
514 }
515
516 return result;
517}
518
519/*
520 * Insert new publication / relation mapping.
521 */
524 bool if_not_exists, AlterPublicationStmt *alter_stmt)
525{
526 Relation rel;
529 bool nulls[Natts_pg_publication_rel];
530 Relation targetrel = pri->relation;
533 Bitmapset *attnums;
534 Publication *pub = GetPublication(pubid);
537 List *relids = NIL;
538 int i;
540
542
543 /*
544 * Check for duplicates. Note that this does not really prevent
545 * duplicates, it's here just to provide nicer error message in common
546 * case. The real protection is the unique key on the catalog.
547 */
549 ObjectIdGetDatum(pubid)))
550 {
552
553 if (if_not_exists)
555
558 errmsg("relation \"%s\" is already member of publication \"%s\"",
560 }
561
563
564 /* Validate and translate column names into a Bitmapset of attnums. */
565 attnums = pub_collist_validate(pri->relation, pri->columns);
566
567 /* Form a tuple. */
568 memset(values, 0, sizeof(values));
569 memset(nulls, false, sizeof(nulls));
570
575 ObjectIdGetDatum(pubid);
577 ObjectIdGetDatum(relid);
579 BoolGetDatum(pri->except);
580
581 /* Add qualifications, if available */
582 if (pri->whereClause != NULL)
584 else
585 nulls[Anum_pg_publication_rel_prqual - 1] = true;
586
587 /* Add column list, if available */
588 if (pri->columns)
590 else
591 nulls[Anum_pg_publication_rel_prattrs - 1] = true;
592
594
595 /* Insert tuple into catalog. */
598
599 /* Register dependencies as needed */
601
602 /* Add dependency on the publication */
605
606 /* Add dependency on the relation */
609
610 /* Add dependency on the objects mentioned in the qualifications */
611 if (pri->whereClause)
612 recordDependencyOnSingleRelExpr(&myself, pri->whereClause, relid,
614 false);
615
616 /* Add dependency on the columns, if any are listed */
617 i = -1;
618 while ((i = bms_next_member(attnums, i)) >= 0)
619 {
622 }
623
624 /* Close the table. */
626
627 /*
628 * Determine whether EXCEPT tables require explicit relcache invalidation.
629 *
630 * For CREATE PUBLICATION with EXCEPT tables, invalidation is skipped
631 * here, as CreatePublication() function invalidates all relations as part
632 * of defining a FOR ALL TABLES publication.
633 *
634 * For ALTER PUBLICATION, invalidation is needed only when adding an
635 * EXCEPT table to a publication already marked as ALL TABLES. For
636 * publications that were originally empty or defined as ALL SEQUENCES and
637 * are being converted to ALL TABLES, invalidation is skipped here, as
638 * AlterPublicationAllFlags() function invalidates all relations while
639 * marking the publication as ALL TABLES publication.
640 */
642 (alter_stmt->for_all_tables && pri->except);
643
644 if (!pri->except || inval_except_table)
645 {
646 /*
647 * Invalidate relcache so that publication info is rebuilt.
648 *
649 * For the partitioned tables, we must invalidate all partitions
650 * contained in the respective partition hierarchies, not just the one
651 * explicitly mentioned in the publication. This is required because
652 * we implicitly publish the child tables when the parent table is
653 * published.
654 */
656 relid);
657
659 }
660
661 return myself;
662}
663
664/*
665 * pub_collist_validate
666 * Process and validate the 'columns' list and ensure the columns are all
667 * valid to use for a publication. Checks for and raises an ERROR for
668 * any unknown columns, system columns, duplicate columns, or virtual
669 * generated columns.
670 *
671 * Looks up each column's attnum and returns a 0-based Bitmapset of the
672 * corresponding attnums.
673 */
674Bitmapset *
676{
677 Bitmapset *set = NULL;
678 ListCell *lc;
680
681 foreach(lc, columns)
682 {
683 char *colname = strVal(lfirst(lc));
685
689 errmsg("column \"%s\" of relation \"%s\" does not exist",
691
695 errmsg("cannot use system column \"%s\" in publication column list",
696 colname));
697
698 if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
701 errmsg("cannot use virtual generated column \"%s\" in publication column list",
702 colname));
703
704 if (bms_is_member(attnum, set))
707 errmsg("duplicate column \"%s\" in publication column list",
708 colname));
709
710 set = bms_add_member(set, attnum);
711 }
712
713 return set;
714}
715
716/*
717 * Transform a column list (represented by an array Datum) to a bitmapset.
718 *
719 * If columns isn't NULL, add the column numbers to that set.
720 *
721 * If mcxt isn't NULL, build the bitmapset in that context.
722 */
723Bitmapset *
725{
726 Bitmapset *result = columns;
727 ArrayType *arr;
728 int nelems;
729 int16 *elems;
731
733 nelems = ARR_DIMS(arr)[0];
734 elems = (int16 *) ARR_DATA_PTR(arr);
735
736 /* If a memory context was specified, switch to it. */
737 if (mcxt)
739
740 for (int i = 0; i < nelems; i++)
741 result = bms_add_member(result, elems[i]);
742
743 if (mcxt)
745
746 return result;
747}
748
749/*
750 * Returns a bitmap representing the columns of the specified table.
751 *
752 * Generated columns are included if include_gencols_type is
753 * PUBLISH_GENCOLS_STORED.
754 */
755Bitmapset *
756pub_form_cols_map(Relation relation, PublishGencolsType include_gencols_type)
757{
759 TupleDesc desc = RelationGetDescr(relation);
760
761 for (int i = 0; i < desc->natts; i++)
762 {
763 Form_pg_attribute att = TupleDescAttr(desc, i);
764
765 if (att->attisdropped)
766 continue;
767
768 if (att->attgenerated)
769 {
770 /* We only support replication of STORED generated cols. */
771 if (att->attgenerated != ATTRIBUTE_GENERATED_STORED)
772 continue;
773
774 /* User hasn't requested to replicate STORED generated cols. */
775 if (include_gencols_type != PUBLISH_GENCOLS_STORED)
776 continue;
777 }
778
779 result = bms_add_member(result, att->attnum);
780 }
781
782 return result;
783}
784
785/*
786 * Insert new publication / schema mapping.
787 */
789publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists)
790{
791 Relation rel;
795 Oid psschid;
796 Publication *pub = GetPublication(pubid);
800
802
803 /*
804 * Check for duplicates. Note that this does not really prevent
805 * duplicates, it's here just to provide nicer error message in common
806 * case. The real protection is the unique key on the catalog.
807 */
810 ObjectIdGetDatum(pubid)))
811 {
813
814 if (if_not_exists)
816
819 errmsg("schema \"%s\" is already member of publication \"%s\"",
821 }
822
824
825 /* Form a tuple */
826 memset(values, 0, sizeof(values));
827 memset(nulls, false, sizeof(nulls));
828
833 ObjectIdGetDatum(pubid);
836
838
839 /* Insert tuple into catalog */
842
844
845 /* Add dependency on the publication */
848
849 /* Add dependency on the schema */
852
853 /* Close the table */
855
856 /*
857 * Invalidate relcache so that publication info is rebuilt. See
858 * publication_add_relation for why we need to consider all the
859 * partitions.
860 */
864
865 return myself;
866}
867
868/*
869 * Internal function to get the list of publication oids for a relation.
870 *
871 * If except_flag is true, returns the list of publication that specified the
872 * relation in the EXCEPT clause; otherwise, returns the list of publications
873 * in which relation is included.
874 */
875static List *
877{
878 List *result = NIL;
880
881 /* Find all publications associated with the relation. */
883 ObjectIdGetDatum(relid));
884 for (int i = 0; i < pubrellist->n_members; i++)
885 {
886 HeapTuple tup = &pubrellist->members[i]->tuple;
888 Oid pubid = pubrel->prpubid;
889
890 if (pubrel->prexcept == except_flag)
891 result = lappend_oid(result, pubid);
892 }
893
895
896 return result;
897}
898
899/*
900 * Gets list of publication oids for a relation.
901 */
902List *
904{
905 return get_relation_publications(relid, false);
906}
907
908/*
909 * Gets list of publication oids which has relation in the EXCEPT clause.
910 */
911List *
913{
914 return get_relation_publications(relid, true);
915}
916
917/*
918 * Internal function to get the list of relation oids for a publication.
919 *
920 * If except_flag is true, returns the list of relations specified in the
921 * EXCEPT clause of the publication; otherwise, returns the list of relations
922 * included in the publication.
923 */
924static List *
926 bool except_flag)
927{
928 List *result;
931 SysScanDesc scan;
933
934 /* Find all relations associated with the publication. */
936
940 ObjectIdGetDatum(pubid));
941
943 true, NULL, 1, &scankey);
944
945 result = NIL;
946 while (HeapTupleIsValid(tup = systable_getnext(scan)))
947 {
949
951
952 if (except_flag == pubrel->prexcept)
954 pubrel->prrelid);
955 }
956
957 systable_endscan(scan);
959
960 /* Now sort and de-duplicate the result list */
963
964 return result;
965}
966
967/*
968 * Gets list of relation oids that are associated with a publication.
969 *
970 * This should only be used FOR TABLE publications, the FOR ALL TABLES/SEQUENCES
971 * should use GetAllPublicationRelations().
972 */
973List *
975{
976 Assert(!GetPublication(pubid)->alltables);
977
978 return get_publication_relations(pubid, pub_partopt, false);
979}
980
981/*
982 * Gets list of table oids that were specified in the EXCEPT clause for a
983 * publication.
984 *
985 * This should only be used FOR ALL TABLES publications.
986 */
987List *
989{
990 Assert(GetPublication(pubid)->alltables);
991
992 return get_publication_relations(pubid, pub_partopt, true);
993}
994
995/*
996 * Gets list of publication oids for publications marked as FOR ALL TABLES.
997 */
998List *
1000{
1001 List *result;
1002 Relation rel;
1004 SysScanDesc scan;
1005 HeapTuple tup;
1006
1007 /* Find all publications that are marked as for all tables. */
1009
1013 BoolGetDatum(true));
1014
1015 scan = systable_beginscan(rel, InvalidOid, false,
1016 NULL, 1, &scankey);
1017
1018 result = NIL;
1019 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1020 {
1021 Oid oid = ((Form_pg_publication) GETSTRUCT(tup))->oid;
1022
1023 result = lappend_oid(result, oid);
1024 }
1025
1026 systable_endscan(scan);
1028
1029 return result;
1030}
1031
1032/*
1033 * Gets list of all relations published by FOR ALL TABLES/SEQUENCES
1034 * publication.
1035 *
1036 * If the publication publishes partition changes via their respective root
1037 * partitioned tables, we must exclude partitions in favor of including the
1038 * root partitioned tables. This is not applicable to FOR ALL SEQUENCES
1039 * publication.
1040 *
1041 * For a FOR ALL TABLES publication, the returned list excludes tables mentioned
1042 * in the EXCEPT clause.
1043 */
1044List *
1045GetAllPublicationRelations(Oid pubid, char relkind, bool pubviaroot)
1046{
1048 ScanKeyData key[1];
1049 TableScanDesc scan;
1050 HeapTuple tuple;
1051 List *result = NIL;
1052 List *exceptlist = NIL;
1053
1054 Assert(!(relkind == RELKIND_SEQUENCE && pubviaroot));
1055
1056 /* EXCEPT filtering applies only to relations, not sequences */
1057 if (relkind == RELKIND_RELATION)
1058 exceptlist = GetExcludedPublicationTables(pubid, pubviaroot ?
1061
1063
1064 ScanKeyInit(&key[0],
1067 CharGetDatum(relkind));
1068
1069 scan = table_beginscan_catalog(classRel, 1, key);
1070
1071 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1072 {
1074 Oid relid = relForm->oid;
1075
1076 if (is_publishable_class(relid, relForm) &&
1077 !(relForm->relispartition && pubviaroot) &&
1078 !list_member_oid(exceptlist, relid))
1079 result = lappend_oid(result, relid);
1080 }
1081
1082 table_endscan(scan);
1083
1084 if (pubviaroot)
1085 {
1086 ScanKeyInit(&key[0],
1090
1091 scan = table_beginscan_catalog(classRel, 1, key);
1092
1093 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1094 {
1096 Oid relid = relForm->oid;
1097
1098 if (is_publishable_class(relid, relForm) &&
1099 !relForm->relispartition &&
1100 !list_member_oid(exceptlist, relid))
1101 result = lappend_oid(result, relid);
1102 }
1103
1104 table_endscan(scan);
1105 }
1106
1108 return result;
1109}
1110
1111/*
1112 * Gets the list of schema oids for a publication.
1113 *
1114 * This should only be used FOR TABLES IN SCHEMA publications.
1115 */
1116List *
1118{
1119 List *result = NIL;
1122 SysScanDesc scan;
1123 HeapTuple tup;
1124
1125 /* Find all schemas associated with the publication */
1127
1131 ObjectIdGetDatum(pubid));
1132
1135 true, NULL, 1, &scankey);
1136 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1137 {
1139
1141
1142 result = lappend_oid(result, pubsch->pnnspid);
1143 }
1144
1145 systable_endscan(scan);
1147
1148 return result;
1149}
1150
1151/*
1152 * Gets the list of publication oids associated with a specified schema.
1153 */
1154List *
1156{
1157 List *result = NIL;
1159 int i;
1160
1161 /* Find all publications associated with the schema */
1164 for (i = 0; i < pubschlist->n_members; i++)
1165 {
1166 HeapTuple tup = &pubschlist->members[i]->tuple;
1168
1169 result = lappend_oid(result, pubid);
1170 }
1171
1173
1174 return result;
1175}
1176
1177/*
1178 * Get the list of publishable relation oids for a specified schema.
1179 */
1180List *
1182{
1184 ScanKeyData key[1];
1185 TableScanDesc scan;
1186 HeapTuple tuple;
1187 List *result = NIL;
1188
1190
1192
1193 ScanKeyInit(&key[0],
1197
1198 /* get all the relations present in the specified schema */
1199 scan = table_beginscan_catalog(classRel, 1, key);
1200 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1201 {
1203 Oid relid = relForm->oid;
1204 char relkind;
1205
1206 if (!is_publishable_class(relid, relForm))
1207 continue;
1208
1209 relkind = get_rel_relkind(relid);
1210 if (relkind == RELKIND_RELATION)
1211 result = lappend_oid(result, relid);
1212 else if (relkind == RELKIND_PARTITIONED_TABLE)
1213 {
1215
1216 /*
1217 * It is quite possible that some of the partitions are in a
1218 * different schema than the parent table, so we need to get such
1219 * partitions separately.
1220 */
1223 relForm->oid);
1225 }
1226 }
1227
1228 table_endscan(scan);
1230 return result;
1231}
1232
1233/*
1234 * Gets the list of all relations published by FOR TABLES IN SCHEMA
1235 * publication.
1236 */
1237List *
1239{
1240 List *result = NIL;
1242 ListCell *cell;
1243
1244 foreach(cell, pubschemalist)
1245 {
1246 Oid schemaid = lfirst_oid(cell);
1247 List *schemaRels = NIL;
1248
1251 }
1252
1253 return result;
1254}
1255
1256/*
1257 * Get publication using oid
1258 *
1259 * The Publication struct and its data are palloc'ed here.
1260 */
1263{
1264 HeapTuple tup;
1265 Publication *pub;
1267
1269 if (!HeapTupleIsValid(tup))
1270 elog(ERROR, "cache lookup failed for publication %u", pubid);
1271
1273
1275 pub->oid = pubid;
1276 pub->name = pstrdup(NameStr(pubform->pubname));
1277 pub->alltables = pubform->puballtables;
1278 pub->allsequences = pubform->puballsequences;
1279 pub->pubactions.pubinsert = pubform->pubinsert;
1280 pub->pubactions.pubupdate = pubform->pubupdate;
1281 pub->pubactions.pubdelete = pubform->pubdelete;
1282 pub->pubactions.pubtruncate = pubform->pubtruncate;
1283 pub->pubviaroot = pubform->pubviaroot;
1284 pub->pubgencols_type = pubform->pubgencols;
1285
1287
1288 return pub;
1289}
1290
1291/*
1292 * Get Publication using name.
1293 */
1295GetPublicationByName(const char *pubname, bool missing_ok)
1296{
1297 Oid oid;
1298
1299 oid = get_publication_oid(pubname, missing_ok);
1300
1301 return OidIsValid(oid) ? GetPublication(oid) : NULL;
1302}
1303
1304/*
1305 * A helper function for pg_get_publication_tables() to check whether the
1306 * table with the given relid is published in the specified publication.
1307 *
1308 * This function evaluates the effective published OID based on the
1309 * publish_via_partition_root setting, rather than just checking catalog entries
1310 * (e.g., pg_publication_rel). For instance, when publish_via_partition_root is
1311 * false, it returns false for a parent partitioned table and returns true
1312 * for its leaf partitions, even if the parent is the one explicitly added
1313 * to the publication.
1314 *
1315 * For performance reasons, this function avoids the overhead of constructing
1316 * the complete list of published tables during the evaluation. It can execute
1317 * quickly even when the publication contains a large number of relations.
1318 *
1319 * Note: this leaks memory for the ancestors list into the current memory
1320 * context.
1321 */
1322static bool
1324{
1325 bool relispartition;
1326 List *ancestors = NIL;
1327
1328 /*
1329 * For non-pubviaroot publications, a partitioned table is never the
1330 * effective published OID; only its leaf partitions can be.
1331 */
1333 return false;
1334
1336
1337 if (relispartition)
1338 ancestors = get_partition_ancestors(relid);
1339
1340 if (pub->alltables)
1341 {
1342 /*
1343 * ALL TABLES with pubviaroot includes only regular tables or top-most
1344 * partitioned tables -- never child partitions.
1345 */
1346 if (pub->pubviaroot && relispartition)
1347 return false;
1348
1349 /*
1350 * For ALL TABLES publications, the table is published unless it
1351 * appears in the EXCEPT clause. Only the top-most can appear in the
1352 * EXCEPT clause, so exclusion must be evaluated at the top-most
1353 * ancestor if it has. These publications store only EXCEPT'ed tables
1354 * in pg_publication_rel, so checking existence is sufficient.
1355 *
1356 * Note that this existence check below would incorrectly return true
1357 * (published) for partitions when pubviaroot is enabled; however,
1358 * that case is already caught and returned false by the above check.
1359 */
1361 ObjectIdGetDatum(ancestors
1362 ? llast_oid(ancestors) : relid),
1363 ObjectIdGetDatum(pub->oid));
1364 }
1365
1366 /*
1367 * Non-ALL-TABLE publication cases.
1368 *
1369 * A table is published if it (or a containing schema) was explicitly
1370 * added, or if it is a partition whose ancestor was added.
1371 */
1372
1373 /*
1374 * If an ancestor is published, the partition's status depends on
1375 * publish_via_partition_root value.
1376 *
1377 * If it's true, the ancestor's relation OID is the effective published
1378 * OID, so the partition itself should be excluded (return false).
1379 *
1380 * If it's false, the partition is covered by its ancestor's presence in
1381 * the publication, it should be included (return true).
1382 */
1383 if (relispartition &&
1385 return !pub->pubviaroot;
1386
1387 /*
1388 * Check whether the table is explicitly published via pg_publication_rel
1389 * or pg_publication_namespace.
1390 */
1392 ObjectIdGetDatum(relid),
1393 ObjectIdGetDatum(pub->oid)) ||
1396 ObjectIdGetDatum(pub->oid)));
1397}
1398
1399/*
1400 * Helper function to get information of the tables in the given
1401 * publication(s).
1402 *
1403 * If filter_by_relid is true, only the row(s) for target_relid is returned;
1404 * if target_relid does not exist or is not part of the publications, zero
1405 * rows are returned. If filter_by_relid is false, rows for all tables
1406 * within the specified publications are returned and target_relid is
1407 * ignored.
1408 *
1409 * Returns pubid, relid, column list, and row filter for each table.
1410 */
1411static Datum
1414 bool pub_missing_ok)
1415{
1416#define NUM_PUBLICATION_TABLES_ELEM 4
1418 List *table_infos = NIL;
1419
1420 /* stuff done only on the first call of the function */
1421 if (SRF_IS_FIRSTCALL())
1422 {
1423 TupleDesc tupdesc;
1424 MemoryContext oldcontext;
1425 Datum *elems;
1426 int nelems,
1427 i;
1428 bool viaroot = false;
1429
1430 /* create a function context for cross-call persistence */
1432
1433 /*
1434 * Preliminary check if the specified table can be published in the
1435 * first place. If not, we can return early without checking the given
1436 * publications and the table.
1437 */
1440
1441 /* switch to memory context appropriate for multiple function calls */
1442 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1443
1444 /*
1445 * Deconstruct the parameter into elements where each element is a
1446 * publication name.
1447 */
1448 deconstruct_array_builtin(pubnames, TEXTOID, &elems, NULL, &nelems);
1449
1450 /* Get Oids of tables from each publication. */
1451 for (i = 0; i < nelems; i++)
1452 {
1455 ListCell *lc;
1456
1459
1460 if (pub_elem == NULL)
1461 continue;
1462
1463 if (filter_by_relid)
1464 {
1465 /* Check if the given table is published for the publication */
1467 {
1469 }
1470 }
1471 else
1472 {
1473 /*
1474 * Publications support partitioned tables. If
1475 * publish_via_partition_root is false, all changes are
1476 * replicated using leaf partition identity and schema, so we
1477 * only need those. Otherwise, get the partitioned table
1478 * itself.
1479 */
1480 if (pub_elem->alltables)
1483 pub_elem->pubviaroot);
1484 else
1485 {
1486 List *relids,
1487 *schemarelids;
1488
1490 pub_elem->pubviaroot ?
1494 pub_elem->pubviaroot ?
1498 }
1499 }
1500
1501 /*
1502 * Record the published table and the corresponding publication so
1503 * that we can get row filters and column lists later.
1504 *
1505 * When a table is published by multiple publications, to obtain
1506 * all row filters and column lists, the structure related to this
1507 * table will be recorded multiple times.
1508 */
1509 foreach(lc, pub_elem_tables)
1510 {
1512
1513 table_info->relid = lfirst_oid(lc);
1514 table_info->pubid = pub_elem->oid;
1516 }
1517
1518 /* At least one publication is using publish_via_partition_root. */
1519 if (pub_elem->pubviaroot)
1520 viaroot = true;
1521 }
1522
1523 /*
1524 * If the publication publishes partition changes via their respective
1525 * root partitioned tables, we must exclude partitions in favor of
1526 * including the root partitioned tables. Otherwise, the function
1527 * could return both the child and parent tables which could cause
1528 * data of the child table to be double-published on the subscriber
1529 * side.
1530 */
1531 if (viaroot)
1533
1534 /* Construct a tuple descriptor for the result rows. */
1536 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "pubid",
1537 OIDOID, -1, 0);
1538 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "relid",
1539 OIDOID, -1, 0);
1540 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "attrs",
1541 INT2VECTOROID, -1, 0);
1542 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "qual",
1543 PG_NODE_TREEOID, -1, 0);
1544
1545 TupleDescFinalize(tupdesc);
1546 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
1547 funcctx->user_fctx = table_infos;
1548
1549 MemoryContextSwitchTo(oldcontext);
1550 }
1551
1552 /* stuff done on every call of the function */
1554 table_infos = (List *) funcctx->user_fctx;
1555
1556 if (funcctx->call_cntr < list_length(table_infos))
1557 {
1560 Publication *pub;
1562 Oid relid = table_info->relid;
1565 bool nulls[NUM_PUBLICATION_TABLES_ELEM] = {0};
1566
1567 /*
1568 * Form tuple with appropriate data.
1569 */
1570
1571 pub = GetPublication(table_info->pubid);
1572
1573 values[0] = ObjectIdGetDatum(pub->oid);
1574 values[1] = ObjectIdGetDatum(relid);
1575
1576 /*
1577 * We don't consider row filters or column lists for FOR ALL TABLES or
1578 * FOR TABLES IN SCHEMA publications.
1579 */
1580 if (!pub->alltables &&
1583 ObjectIdGetDatum(pub->oid)))
1585 ObjectIdGetDatum(relid),
1586 ObjectIdGetDatum(pub->oid));
1587
1589 {
1590 /* Lookup the column list attribute. */
1593 &(nulls[2]));
1594
1595 /* Null indicates no filter. */
1598 &(nulls[3]));
1599 }
1600 else
1601 {
1602 nulls[2] = true;
1603 nulls[3] = true;
1604 }
1605
1606 /* Show all columns when the column list is not specified. */
1607 if (nulls[2])
1608 {
1609 Relation rel = table_open(relid, AccessShareLock);
1610 int nattnums = 0;
1611 int16 *attnums;
1612 TupleDesc desc = RelationGetDescr(rel);
1613 int i;
1614
1615 attnums = palloc_array(int16, desc->natts);
1616
1617 for (i = 0; i < desc->natts; i++)
1618 {
1619 Form_pg_attribute att = TupleDescAttr(desc, i);
1620
1621 if (att->attisdropped)
1622 continue;
1623
1624 if (att->attgenerated)
1625 {
1626 /* We only support replication of STORED generated cols. */
1627 if (att->attgenerated != ATTRIBUTE_GENERATED_STORED)
1628 continue;
1629
1630 /*
1631 * User hasn't requested to replicate STORED generated
1632 * cols.
1633 */
1635 continue;
1636 }
1637
1638 attnums[nattnums++] = att->attnum;
1639 }
1640
1641 if (nattnums > 0)
1642 {
1643 values[2] = PointerGetDatum(buildint2vector(attnums, nattnums));
1644 nulls[2] = false;
1645 }
1646
1648 }
1649
1650 rettuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
1651
1653 }
1654
1656}
1657
1658Datum
1660{
1661 /*
1662 * Get information for all tables in the given publications.
1663 * filter_by_relid is false so all tables are returned; pub_missing_ok is
1664 * false for backward compatibility.
1665 */
1667 InvalidOid, false, false);
1668}
1669
1670Datum
1672{
1673 /*
1674 * Get information for the specified table in the given publications. The
1675 * SQL-level function is declared STRICT, so target_relid is guaranteed to
1676 * be non-NULL here.
1677 */
1679 PG_GETARG_OID(1), true, true);
1680}
1681
1682/*
1683 * Returns Oids of sequences in a publication.
1684 */
1685Datum
1687{
1689 List *sequences = NIL;
1690
1691 /* stuff done only on the first call of the function */
1692 if (SRF_IS_FIRSTCALL())
1693 {
1694 char *pubname = text_to_cstring(PG_GETARG_TEXT_PP(0));
1695 Publication *publication;
1696 MemoryContext oldcontext;
1697
1698 /* create a function context for cross-call persistence */
1700
1701 /* switch to memory context appropriate for multiple function calls */
1702 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1703
1704 publication = GetPublicationByName(pubname, false);
1705
1706 if (publication->allsequences)
1709 false);
1710
1711 funcctx->user_fctx = sequences;
1712
1713 MemoryContextSwitchTo(oldcontext);
1714 }
1715
1716 /* stuff done on every call of the function */
1718 sequences = (List *) funcctx->user_fctx;
1719
1720 if (funcctx->call_cntr < list_length(sequences))
1721 {
1722 Oid relid = list_nth_oid(sequences, funcctx->call_cntr);
1723
1725 }
1726
1728}
#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:1290
int bms_num_members(const Bitmapset *a)
Definition bitmapset.c:744
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:510
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:799
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:835
#define gettext_noop(x)
Definition c.h:1285
#define Assert(condition)
Definition c.h:943
int16_t int16
Definition c.h:619
#define PG_INT16_MAX
Definition c.h:670
#define OidIsValid(objectId)
Definition c.h:858
bool IsToastNamespace(Oid namespaceId)
Definition catalog.c:261
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition catalog.c:448
bool IsCatalogNamespace(Oid namespaceId)
Definition catalog.c:243
bool IsCatalogRelation(Relation relation)
Definition catalog.c:104
bool IsCatalogRelationOid(Oid relid)
Definition catalog.c:121
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:74
#define palloc_array(type, count)
Definition fe_memutils.h:76
#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:612
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:523
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:2258
AttrNumber get_attnum(Oid relid, const char *attname)
Definition lsyscache.c:1015
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2234
Oid get_publication_oid(const char *pubname, bool missing_ok)
Definition lsyscache.c:3903
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2183
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3599
char * pstrdup(const char *in)
Definition mcxt.c:1781
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:124
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:47
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
char * RelationGetQualifiedRelationName(Relation rel)
Definition relcache.c:2142
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:900
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