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 *errormsg;
60
61 if (pri->except)
62 errormsg = gettext_noop("cannot specify relation \"%s\" in the publication EXCEPT clause");
63 else
64 errormsg = gettext_noop("cannot add relation \"%s\" to publication");
65
66 /* If in EXCEPT clause, must be root partitioned table */
67 if (pri->except && targetrel->rd_rel->relispartition)
71 errdetail("This operation is not supported for individual partitions.")));
72
73 /* Must be a regular or partitioned table */
80
81 /* Can't be system table */
86 errdetail("This operation is not supported for system tables.")));
87
88 /* UNLOGGED and TEMP relations cannot be part of publication. */
89 if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
93 errdetail("This operation is not supported for temporary tables.")));
94 else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
98 errdetail("This operation is not supported for unlogged tables.")));
99}
100
101/*
102 * Check if schema can be in given publication and throw appropriate error if
103 * not.
104 */
105static void
107{
108 /* Can't be system namespace */
112 errmsg("cannot add schema \"%s\" to publication",
114 errdetail("This operation is not supported for system schemas.")));
115
116 /* Can't be temporary namespace */
120 errmsg("cannot add schema \"%s\" to publication",
122 errdetail("Temporary schemas cannot be replicated.")));
123}
124
125/*
126 * Returns if relation represented by oid and Form_pg_class entry
127 * is publishable.
128 *
129 * Does same checks as check_publication_add_relation() above except for
130 * RELKIND_SEQUENCE, but does not need relation to be opened and also does
131 * not throw errors. Here, the additional check is to support ALL SEQUENCES
132 * publication.
133 *
134 * XXX This also excludes all tables with relid < FirstNormalObjectId,
135 * ie all tables created during initdb. This mainly affects the preinstalled
136 * information_schema. IsCatalogRelationOid() only excludes tables with
137 * relid < FirstUnpinnedObjectId, making that test rather redundant,
138 * but really we should get rid of the FirstNormalObjectId test not
139 * IsCatalogRelationOid. We can't do so today because we don't want
140 * information_schema tables to be considered publishable; but this test
141 * is really inadequate for that, since the information_schema could be
142 * dropped and reloaded and then it'll be considered publishable. The best
143 * long-term solution may be to add a "relispublishable" bool to pg_class,
144 * and depend on that instead of OID checks.
145 */
146static bool
148{
149 return (reltuple->relkind == RELKIND_RELATION ||
151 reltuple->relkind == RELKIND_SEQUENCE) &&
152 !IsCatalogRelationOid(relid) &&
153 reltuple->relpersistence == RELPERSISTENCE_PERMANENT &&
154 relid >= FirstNormalObjectId;
155}
156
157/*
158 * Another variant of is_publishable_class(), taking a Relation.
159 */
160bool
165
166/*
167 * Similar to is_publishable_class() but checks whether the given OID
168 * is a publishable "table" or not.
169 */
170static bool
172{
173 HeapTuple tuple;
175
176 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(tableoid));
177 if (!HeapTupleIsValid(tuple))
178 return false;
179
181
182 /*
183 * is_publishable_class() includes sequences, so we need to explicitly
184 * check the relkind to filter them out here.
185 */
186 if (relform->relkind != RELKIND_SEQUENCE &&
187 is_publishable_class(tableoid, relform))
188 {
189 ReleaseSysCache(tuple);
190 return true;
191 }
192
193 ReleaseSysCache(tuple);
194 return false;
195}
196
197/*
198 * SQL-callable variant of the above
199 *
200 * This returns null when the relation does not exist. This is intended to be
201 * used for example in psql to avoid gratuitous errors when there are
202 * concurrent catalog changes.
203 */
204Datum
206{
207 Oid relid = PG_GETARG_OID(0);
208 HeapTuple tuple;
209 bool result;
210
211 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
212 if (!HeapTupleIsValid(tuple))
215 ReleaseSysCache(tuple);
217}
218
219/*
220 * Returns true if the ancestor is in the list of published relations.
221 * Otherwise, returns false.
222 */
223static bool
225{
226 ListCell *lc;
227
228 foreach(lc, table_infos)
229 {
230 Oid relid = ((published_rel *) lfirst(lc))->relid;
231
232 if (relid == ancestor)
233 return true;
234 }
235
236 return false;
237}
238
239/*
240 * Filter out the partitions whose parent tables are also present in the list.
241 */
242static void
244{
245 ListCell *lc;
246
247 foreach(lc, table_infos)
248 {
249 bool skip = false;
250 List *ancestors = NIL;
251 ListCell *lc2;
253
255 ancestors = get_partition_ancestors(table_info->relid);
256
257 foreach(lc2, ancestors)
258 {
260
262 {
263 skip = true;
264 break;
265 }
266 }
267
268 if (skip)
270 }
271}
272
273/*
274 * Returns true if any schema is associated with the publication, false if no
275 * schema is associated with the publication.
276 */
277bool
303
304/*
305 * Returns true if the publication has explicitly included relation (i.e.,
306 * not marked as EXCEPT).
307 */
308bool
310{
313 SysScanDesc scan;
315 bool result = false;
316
321 ObjectIdGetDatum(pubid));
322
325 true, NULL, 1, &scankey);
326 tup = systable_getnext(scan);
328 {
330
332
333 /*
334 * For any publication, pg_publication_rel contains either only EXCEPT
335 * entries or only explicitly included tables. Therefore, examining
336 * the first tuple is sufficient to determine table inclusion.
337 */
338 result = !pubrel->prexcept;
339 }
340
341 systable_endscan(scan);
343
344 return result;
345}
346
347/*
348 * Returns true if the relation has column list associated with the
349 * publication, false otherwise.
350 *
351 * If a column list is found, the corresponding bitmap is returned through the
352 * cols parameter, if provided. The bitmap is constructed within the given
353 * memory context (mcxt).
354 */
355bool
357 Bitmapset **cols)
358{
360 bool found = false;
361
362 if (pub->alltables)
363 return false;
364
366 ObjectIdGetDatum(relid),
367 ObjectIdGetDatum(pub->oid));
369 {
371 bool isnull;
372
373 /* Lookup the column list attribute. */
376
377 /* Was a column list found? */
378 if (!isnull)
379 {
380 /* Build the column list bitmap in the given memory context. */
381 if (cols)
382 *cols = pub_collist_to_bitmapset(*cols, cfdatum, mcxt);
383
384 found = true;
385 }
386
388 }
389
390 return found;
391}
392
393/*
394 * Gets the relations based on the publication partition option for a specified
395 * relation.
396 */
397List *
399 Oid relid)
400{
403 {
405 NULL);
406
410 {
411 ListCell *lc;
412
413 foreach(lc, all_parts)
414 {
416
419 }
420 }
421 else
422 Assert(false);
423 }
424 else
425 result = lappend_oid(result, relid);
426
427 return result;
428}
429
430/*
431 * Returns the relid of the topmost ancestor that is published via this
432 * publication if any and set its ancestor level to ancestor_level,
433 * otherwise returns InvalidOid.
434 *
435 * The ancestor_level value allows us to compare the results for multiple
436 * publications, and decide which value is higher up.
437 *
438 * Note that the list of ancestors should be ordered such that the topmost
439 * ancestor is at the end of the list.
440 */
441Oid
443{
444 ListCell *lc;
446 int level = 0;
447
448 /*
449 * Find the "topmost" ancestor that is in this publication.
450 */
451 foreach(lc, ancestors)
452 {
456
457 level++;
458
460 {
462
463 if (ancestor_level)
464 *ancestor_level = level;
465 }
466 else
467 {
470 {
472
473 if (ancestor_level)
474 *ancestor_level = level;
475 }
476 }
477
480 }
481
482 return topmost_relid;
483}
484
485/*
486 * attnumstoint2vector
487 * Convert a Bitmapset of AttrNumbers into an int2vector.
488 *
489 * AttrNumber numbers are 0-based, i.e., not offset by
490 * FirstLowInvalidHeapAttributeNumber.
491 */
492static int2vector *
494{
496 int n = bms_num_members(attrs);
497 int i = -1;
498 int j = 0;
499
501
502 while ((i = bms_next_member(attrs, i)) >= 0)
503 {
505
506 result->values[j++] = (int16) i;
507 }
508
509 return result;
510}
511
512/*
513 * Insert new publication / relation mapping.
514 */
517 bool if_not_exists, AlterPublicationStmt *alter_stmt)
518{
519 Relation rel;
522 bool nulls[Natts_pg_publication_rel];
523 Relation targetrel = pri->relation;
526 Bitmapset *attnums;
527 Publication *pub = GetPublication(pubid);
530 List *relids = NIL;
531 int i;
533
535
536 /*
537 * Check for duplicates. Note that this does not really prevent
538 * duplicates, it's here just to provide nicer error message in common
539 * case. The real protection is the unique key on the catalog.
540 */
542 ObjectIdGetDatum(pubid)))
543 {
545
546 if (if_not_exists)
548
551 errmsg("relation \"%s\" is already member of publication \"%s\"",
553 }
554
556
557 /* Validate and translate column names into a Bitmapset of attnums. */
558 attnums = pub_collist_validate(pri->relation, pri->columns);
559
560 /* Form a tuple. */
561 memset(values, 0, sizeof(values));
562 memset(nulls, false, sizeof(nulls));
563
568 ObjectIdGetDatum(pubid);
570 ObjectIdGetDatum(relid);
572 BoolGetDatum(pri->except);
573
574 /* Add qualifications, if available */
575 if (pri->whereClause != NULL)
577 else
578 nulls[Anum_pg_publication_rel_prqual - 1] = true;
579
580 /* Add column list, if available */
581 if (pri->columns)
583 else
584 nulls[Anum_pg_publication_rel_prattrs - 1] = true;
585
587
588 /* Insert tuple into catalog. */
591
592 /* Register dependencies as needed */
594
595 /* Add dependency on the publication */
598
599 /* Add dependency on the relation */
602
603 /* Add dependency on the objects mentioned in the qualifications */
604 if (pri->whereClause)
605 recordDependencyOnSingleRelExpr(&myself, pri->whereClause, relid,
607 false);
608
609 /* Add dependency on the columns, if any are listed */
610 i = -1;
611 while ((i = bms_next_member(attnums, i)) >= 0)
612 {
615 }
616
617 /* Close the table. */
619
620 /*
621 * Determine whether EXCEPT tables require explicit relcache invalidation.
622 *
623 * For CREATE PUBLICATION with EXCEPT tables, invalidation is skipped
624 * here, as CreatePublication() function invalidates all relations as part
625 * of defining a FOR ALL TABLES publication.
626 *
627 * For ALTER PUBLICATION, invalidation is needed only when adding an
628 * EXCEPT table to a publication already marked as ALL TABLES. For
629 * publications that were originally empty or defined as ALL SEQUENCES and
630 * are being converted to ALL TABLES, invalidation is skipped here, as
631 * AlterPublicationAllFlags() function invalidates all relations while
632 * marking the publication as ALL TABLES publication.
633 */
635 (alter_stmt->for_all_tables && pri->except);
636
637 if (!pri->except || inval_except_table)
638 {
639 /*
640 * Invalidate relcache so that publication info is rebuilt.
641 *
642 * For the partitioned tables, we must invalidate all partitions
643 * contained in the respective partition hierarchies, not just the one
644 * explicitly mentioned in the publication. This is required because
645 * we implicitly publish the child tables when the parent table is
646 * published.
647 */
649 relid);
650
652 }
653
654 return myself;
655}
656
657/*
658 * pub_collist_validate
659 * Process and validate the 'columns' list and ensure the columns are all
660 * valid to use for a publication. Checks for and raises an ERROR for
661 * any unknown columns, system columns, duplicate columns, or virtual
662 * generated columns.
663 *
664 * Looks up each column's attnum and returns a 0-based Bitmapset of the
665 * corresponding attnums.
666 */
667Bitmapset *
669{
670 Bitmapset *set = NULL;
671 ListCell *lc;
673
674 foreach(lc, columns)
675 {
676 char *colname = strVal(lfirst(lc));
678
682 errmsg("column \"%s\" of relation \"%s\" does not exist",
684
688 errmsg("cannot use system column \"%s\" in publication column list",
689 colname));
690
691 if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
694 errmsg("cannot use virtual generated column \"%s\" in publication column list",
695 colname));
696
697 if (bms_is_member(attnum, set))
700 errmsg("duplicate column \"%s\" in publication column list",
701 colname));
702
703 set = bms_add_member(set, attnum);
704 }
705
706 return set;
707}
708
709/*
710 * Transform a column list (represented by an array Datum) to a bitmapset.
711 *
712 * If columns isn't NULL, add the column numbers to that set.
713 *
714 * If mcxt isn't NULL, build the bitmapset in that context.
715 */
716Bitmapset *
718{
719 Bitmapset *result = columns;
720 ArrayType *arr;
721 int nelems;
722 int16 *elems;
724
726 nelems = ARR_DIMS(arr)[0];
727 elems = (int16 *) ARR_DATA_PTR(arr);
728
729 /* If a memory context was specified, switch to it. */
730 if (mcxt)
732
733 for (int i = 0; i < nelems; i++)
734 result = bms_add_member(result, elems[i]);
735
736 if (mcxt)
738
739 return result;
740}
741
742/*
743 * Returns a bitmap representing the columns of the specified table.
744 *
745 * Generated columns are included if include_gencols_type is
746 * PUBLISH_GENCOLS_STORED.
747 */
748Bitmapset *
749pub_form_cols_map(Relation relation, PublishGencolsType include_gencols_type)
750{
752 TupleDesc desc = RelationGetDescr(relation);
753
754 for (int i = 0; i < desc->natts; i++)
755 {
756 Form_pg_attribute att = TupleDescAttr(desc, i);
757
758 if (att->attisdropped)
759 continue;
760
761 if (att->attgenerated)
762 {
763 /* We only support replication of STORED generated cols. */
764 if (att->attgenerated != ATTRIBUTE_GENERATED_STORED)
765 continue;
766
767 /* User hasn't requested to replicate STORED generated cols. */
768 if (include_gencols_type != PUBLISH_GENCOLS_STORED)
769 continue;
770 }
771
772 result = bms_add_member(result, att->attnum);
773 }
774
775 return result;
776}
777
778/*
779 * Insert new publication / schema mapping.
780 */
782publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists)
783{
784 Relation rel;
788 Oid psschid;
789 Publication *pub = GetPublication(pubid);
793
795
796 /*
797 * Check for duplicates. Note that this does not really prevent
798 * duplicates, it's here just to provide nicer error message in common
799 * case. The real protection is the unique key on the catalog.
800 */
803 ObjectIdGetDatum(pubid)))
804 {
806
807 if (if_not_exists)
809
812 errmsg("schema \"%s\" is already member of publication \"%s\"",
814 }
815
817
818 /* Form a tuple */
819 memset(values, 0, sizeof(values));
820 memset(nulls, false, sizeof(nulls));
821
826 ObjectIdGetDatum(pubid);
829
831
832 /* Insert tuple into catalog */
835
837
838 /* Add dependency on the publication */
841
842 /* Add dependency on the schema */
845
846 /* Close the table */
848
849 /*
850 * Invalidate relcache so that publication info is rebuilt. See
851 * publication_add_relation for why we need to consider all the
852 * partitions.
853 */
857
858 return myself;
859}
860
861/*
862 * Internal function to get the list of publication oids for a relation.
863 *
864 * If except_flag is true, returns the list of publication that specified the
865 * relation in the EXCEPT clause; otherwise, returns the list of publications
866 * in which relation is included.
867 */
868static List *
870{
871 List *result = NIL;
873
874 /* Find all publications associated with the relation. */
876 ObjectIdGetDatum(relid));
877 for (int i = 0; i < pubrellist->n_members; i++)
878 {
879 HeapTuple tup = &pubrellist->members[i]->tuple;
881 Oid pubid = pubrel->prpubid;
882
883 if (pubrel->prexcept == except_flag)
884 result = lappend_oid(result, pubid);
885 }
886
888
889 return result;
890}
891
892/*
893 * Gets list of publication oids for a relation.
894 */
895List *
897{
898 return get_relation_publications(relid, false);
899}
900
901/*
902 * Gets list of publication oids which has relation in the EXCEPT clause.
903 */
904List *
906{
907 return get_relation_publications(relid, true);
908}
909
910/*
911 * Internal function to get the list of relation oids for a publication.
912 *
913 * If except_flag is true, returns the list of relations specified in the
914 * EXCEPT clause of the publication; otherwise, returns the list of relations
915 * included in the publication.
916 */
917static List *
919 bool except_flag)
920{
921 List *result;
924 SysScanDesc scan;
926
927 /* Find all relations associated with the publication. */
929
933 ObjectIdGetDatum(pubid));
934
936 true, NULL, 1, &scankey);
937
938 result = NIL;
939 while (HeapTupleIsValid(tup = systable_getnext(scan)))
940 {
942
944
945 if (except_flag == pubrel->prexcept)
947 pubrel->prrelid);
948 }
949
950 systable_endscan(scan);
952
953 /* Now sort and de-duplicate the result list */
956
957 return result;
958}
959
960/*
961 * Gets list of relation oids that are associated with a publication.
962 *
963 * This should only be used FOR TABLE publications, the FOR ALL TABLES/SEQUENCES
964 * should use GetAllPublicationRelations().
965 */
966List *
968{
969 Assert(!GetPublication(pubid)->alltables);
970
971 return get_publication_relations(pubid, pub_partopt, false);
972}
973
974/*
975 * Gets list of table oids that were specified in the EXCEPT clause for a
976 * publication.
977 *
978 * This should only be used FOR ALL TABLES publications.
979 */
980List *
982{
983 Assert(GetPublication(pubid)->alltables);
984
985 return get_publication_relations(pubid, pub_partopt, true);
986}
987
988/*
989 * Gets list of publication oids for publications marked as FOR ALL TABLES.
990 */
991List *
993{
994 List *result;
995 Relation rel;
997 SysScanDesc scan;
999
1000 /* Find all publications that are marked as for all tables. */
1002
1006 BoolGetDatum(true));
1007
1008 scan = systable_beginscan(rel, InvalidOid, false,
1009 NULL, 1, &scankey);
1010
1011 result = NIL;
1012 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1013 {
1014 Oid oid = ((Form_pg_publication) GETSTRUCT(tup))->oid;
1015
1016 result = lappend_oid(result, oid);
1017 }
1018
1019 systable_endscan(scan);
1021
1022 return result;
1023}
1024
1025/*
1026 * Gets list of all relations published by FOR ALL TABLES/SEQUENCES
1027 * publication.
1028 *
1029 * If the publication publishes partition changes via their respective root
1030 * partitioned tables, we must exclude partitions in favor of including the
1031 * root partitioned tables. This is not applicable to FOR ALL SEQUENCES
1032 * publication.
1033 *
1034 * For a FOR ALL TABLES publication, the returned list excludes tables mentioned
1035 * in the EXCEPT clause.
1036 */
1037List *
1038GetAllPublicationRelations(Oid pubid, char relkind, bool pubviaroot)
1039{
1041 ScanKeyData key[1];
1042 TableScanDesc scan;
1043 HeapTuple tuple;
1044 List *result = NIL;
1045 List *exceptlist = NIL;
1046
1047 Assert(!(relkind == RELKIND_SEQUENCE && pubviaroot));
1048
1049 /* EXCEPT filtering applies only to relations, not sequences */
1050 if (relkind == RELKIND_RELATION)
1051 exceptlist = GetExcludedPublicationTables(pubid, pubviaroot ?
1054
1056
1057 ScanKeyInit(&key[0],
1060 CharGetDatum(relkind));
1061
1062 scan = table_beginscan_catalog(classRel, 1, key);
1063
1064 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1065 {
1067 Oid relid = relForm->oid;
1068
1069 if (is_publishable_class(relid, relForm) &&
1070 !(relForm->relispartition && pubviaroot) &&
1071 !list_member_oid(exceptlist, relid))
1072 result = lappend_oid(result, relid);
1073 }
1074
1075 table_endscan(scan);
1076
1077 if (pubviaroot)
1078 {
1079 ScanKeyInit(&key[0],
1083
1084 scan = table_beginscan_catalog(classRel, 1, key);
1085
1086 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1087 {
1089 Oid relid = relForm->oid;
1090
1091 if (is_publishable_class(relid, relForm) &&
1092 !relForm->relispartition &&
1093 !list_member_oid(exceptlist, relid))
1094 result = lappend_oid(result, relid);
1095 }
1096
1097 table_endscan(scan);
1098 }
1099
1101 return result;
1102}
1103
1104/*
1105 * Gets the list of schema oids for a publication.
1106 *
1107 * This should only be used FOR TABLES IN SCHEMA publications.
1108 */
1109List *
1111{
1112 List *result = NIL;
1115 SysScanDesc scan;
1116 HeapTuple tup;
1117
1118 /* Find all schemas associated with the publication */
1120
1124 ObjectIdGetDatum(pubid));
1125
1128 true, NULL, 1, &scankey);
1129 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1130 {
1132
1134
1135 result = lappend_oid(result, pubsch->pnnspid);
1136 }
1137
1138 systable_endscan(scan);
1140
1141 return result;
1142}
1143
1144/*
1145 * Gets the list of publication oids associated with a specified schema.
1146 */
1147List *
1149{
1150 List *result = NIL;
1152 int i;
1153
1154 /* Find all publications associated with the schema */
1157 for (i = 0; i < pubschlist->n_members; i++)
1158 {
1159 HeapTuple tup = &pubschlist->members[i]->tuple;
1161
1162 result = lappend_oid(result, pubid);
1163 }
1164
1166
1167 return result;
1168}
1169
1170/*
1171 * Get the list of publishable relation oids for a specified schema.
1172 */
1173List *
1175{
1177 ScanKeyData key[1];
1178 TableScanDesc scan;
1179 HeapTuple tuple;
1180 List *result = NIL;
1181
1183
1185
1186 ScanKeyInit(&key[0],
1190
1191 /* get all the relations present in the specified schema */
1192 scan = table_beginscan_catalog(classRel, 1, key);
1193 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1194 {
1196 Oid relid = relForm->oid;
1197 char relkind;
1198
1199 if (!is_publishable_class(relid, relForm))
1200 continue;
1201
1202 relkind = get_rel_relkind(relid);
1203 if (relkind == RELKIND_RELATION)
1204 result = lappend_oid(result, relid);
1205 else if (relkind == RELKIND_PARTITIONED_TABLE)
1206 {
1208
1209 /*
1210 * It is quite possible that some of the partitions are in a
1211 * different schema than the parent table, so we need to get such
1212 * partitions separately.
1213 */
1216 relForm->oid);
1218 }
1219 }
1220
1221 table_endscan(scan);
1223 return result;
1224}
1225
1226/*
1227 * Gets the list of all relations published by FOR TABLES IN SCHEMA
1228 * publication.
1229 */
1230List *
1232{
1233 List *result = NIL;
1235 ListCell *cell;
1236
1237 foreach(cell, pubschemalist)
1238 {
1239 Oid schemaid = lfirst_oid(cell);
1240 List *schemaRels = NIL;
1241
1244 }
1245
1246 return result;
1247}
1248
1249/*
1250 * Get publication using oid
1251 *
1252 * The Publication struct and its data are palloc'ed here.
1253 */
1256{
1257 HeapTuple tup;
1258 Publication *pub;
1260
1262 if (!HeapTupleIsValid(tup))
1263 elog(ERROR, "cache lookup failed for publication %u", pubid);
1264
1266
1268 pub->oid = pubid;
1269 pub->name = pstrdup(NameStr(pubform->pubname));
1270 pub->alltables = pubform->puballtables;
1271 pub->allsequences = pubform->puballsequences;
1272 pub->pubactions.pubinsert = pubform->pubinsert;
1273 pub->pubactions.pubupdate = pubform->pubupdate;
1274 pub->pubactions.pubdelete = pubform->pubdelete;
1275 pub->pubactions.pubtruncate = pubform->pubtruncate;
1276 pub->pubviaroot = pubform->pubviaroot;
1277 pub->pubgencols_type = pubform->pubgencols;
1278
1280
1281 return pub;
1282}
1283
1284/*
1285 * Get Publication using name.
1286 */
1288GetPublicationByName(const char *pubname, bool missing_ok)
1289{
1290 Oid oid;
1291
1292 oid = get_publication_oid(pubname, missing_ok);
1293
1294 return OidIsValid(oid) ? GetPublication(oid) : NULL;
1295}
1296
1297/*
1298 * A helper function for pg_get_publication_tables() to check whether the
1299 * table with the given relid is published in the specified publication.
1300 *
1301 * This function evaluates the effective published OID based on the
1302 * publish_via_partition_root setting, rather than just checking catalog entries
1303 * (e.g., pg_publication_rel). For instance, when publish_via_partition_root is
1304 * false, it returns false for a parent partitioned table and returns true
1305 * for its leaf partitions, even if the parent is the one explicitly added
1306 * to the publication.
1307 *
1308 * For performance reasons, this function avoids the overhead of constructing
1309 * the complete list of published tables during the evaluation. It can execute
1310 * quickly even when the publication contains a large number of relations.
1311 *
1312 * Note: this leaks memory for the ancestors list into the current memory
1313 * context.
1314 */
1315static bool
1317{
1318 bool relispartition;
1319 List *ancestors = NIL;
1320
1321 /*
1322 * For non-pubviaroot publications, a partitioned table is never the
1323 * effective published OID; only its leaf partitions can be.
1324 */
1326 return false;
1327
1329
1330 if (relispartition)
1331 ancestors = get_partition_ancestors(relid);
1332
1333 if (pub->alltables)
1334 {
1335 /*
1336 * ALL TABLES with pubviaroot includes only regular tables or top-most
1337 * partitioned tables -- never child partitions.
1338 */
1339 if (pub->pubviaroot && relispartition)
1340 return false;
1341
1342 /*
1343 * For ALL TABLES publications, the table is published unless it
1344 * appears in the EXCEPT clause. Only the top-most can appear in the
1345 * EXCEPT clause, so exclusion must be evaluated at the top-most
1346 * ancestor if it has. These publications store only EXCEPT'ed tables
1347 * in pg_publication_rel, so checking existence is sufficient.
1348 *
1349 * Note that this existence check below would incorrectly return true
1350 * (published) for partitions when pubviaroot is enabled; however,
1351 * that case is already caught and returned false by the above check.
1352 */
1354 ObjectIdGetDatum(ancestors
1355 ? llast_oid(ancestors) : relid),
1356 ObjectIdGetDatum(pub->oid));
1357 }
1358
1359 /*
1360 * Non-ALL-TABLE publication cases.
1361 *
1362 * A table is published if it (or a containing schema) was explicitly
1363 * added, or if it is a partition whose ancestor was added.
1364 */
1365
1366 /*
1367 * If an ancestor is published, the partition's status depends on
1368 * publish_via_partition_root value.
1369 *
1370 * If it's true, the ancestor's relation OID is the effective published
1371 * OID, so the partition itself should be excluded (return false).
1372 *
1373 * If it's false, the partition is covered by its ancestor's presence in
1374 * the publication, it should be included (return true).
1375 */
1376 if (relispartition &&
1378 return !pub->pubviaroot;
1379
1380 /*
1381 * Check whether the table is explicitly published via pg_publication_rel
1382 * or pg_publication_namespace.
1383 */
1385 ObjectIdGetDatum(relid),
1386 ObjectIdGetDatum(pub->oid)) ||
1389 ObjectIdGetDatum(pub->oid)));
1390}
1391
1392/*
1393 * Helper function to get information of the tables in the given
1394 * publication(s).
1395 *
1396 * If filter_by_relid is true, only the row(s) for target_relid is returned;
1397 * if target_relid does not exist or is not part of the publications, zero
1398 * rows are returned. If filter_by_relid is false, rows for all tables
1399 * within the specified publications are returned and target_relid is
1400 * ignored.
1401 *
1402 * Returns pubid, relid, column list, and row filter for each table.
1403 */
1404static Datum
1407 bool pub_missing_ok)
1408{
1409#define NUM_PUBLICATION_TABLES_ELEM 4
1411 List *table_infos = NIL;
1412
1413 /* stuff done only on the first call of the function */
1414 if (SRF_IS_FIRSTCALL())
1415 {
1416 TupleDesc tupdesc;
1417 MemoryContext oldcontext;
1418 Datum *elems;
1419 int nelems,
1420 i;
1421 bool viaroot = false;
1422
1423 /* create a function context for cross-call persistence */
1425
1426 /*
1427 * Preliminary check if the specified table can be published in the
1428 * first place. If not, we can return early without checking the given
1429 * publications and the table.
1430 */
1433
1434 /* switch to memory context appropriate for multiple function calls */
1435 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1436
1437 /*
1438 * Deconstruct the parameter into elements where each element is a
1439 * publication name.
1440 */
1441 deconstruct_array_builtin(pubnames, TEXTOID, &elems, NULL, &nelems);
1442
1443 /* Get Oids of tables from each publication. */
1444 for (i = 0; i < nelems; i++)
1445 {
1448 ListCell *lc;
1449
1452
1453 if (pub_elem == NULL)
1454 continue;
1455
1456 if (filter_by_relid)
1457 {
1458 /* Check if the given table is published for the publication */
1460 {
1462 }
1463 }
1464 else
1465 {
1466 /*
1467 * Publications support partitioned tables. If
1468 * publish_via_partition_root is false, all changes are
1469 * replicated using leaf partition identity and schema, so we
1470 * only need those. Otherwise, get the partitioned table
1471 * itself.
1472 */
1473 if (pub_elem->alltables)
1476 pub_elem->pubviaroot);
1477 else
1478 {
1479 List *relids,
1480 *schemarelids;
1481
1483 pub_elem->pubviaroot ?
1487 pub_elem->pubviaroot ?
1491 }
1492 }
1493
1494 /*
1495 * Record the published table and the corresponding publication so
1496 * that we can get row filters and column lists later.
1497 *
1498 * When a table is published by multiple publications, to obtain
1499 * all row filters and column lists, the structure related to this
1500 * table will be recorded multiple times.
1501 */
1502 foreach(lc, pub_elem_tables)
1503 {
1505
1506 table_info->relid = lfirst_oid(lc);
1507 table_info->pubid = pub_elem->oid;
1509 }
1510
1511 /* At least one publication is using publish_via_partition_root. */
1512 if (pub_elem->pubviaroot)
1513 viaroot = true;
1514 }
1515
1516 /*
1517 * If the publication publishes partition changes via their respective
1518 * root partitioned tables, we must exclude partitions in favor of
1519 * including the root partitioned tables. Otherwise, the function
1520 * could return both the child and parent tables which could cause
1521 * data of the child table to be double-published on the subscriber
1522 * side.
1523 */
1524 if (viaroot)
1526
1527 /* Construct a tuple descriptor for the result rows. */
1529 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "pubid",
1530 OIDOID, -1, 0);
1531 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "relid",
1532 OIDOID, -1, 0);
1533 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "attrs",
1534 INT2VECTOROID, -1, 0);
1535 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "qual",
1536 PG_NODE_TREEOID, -1, 0);
1537
1538 TupleDescFinalize(tupdesc);
1539 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
1540 funcctx->user_fctx = table_infos;
1541
1542 MemoryContextSwitchTo(oldcontext);
1543 }
1544
1545 /* stuff done on every call of the function */
1547 table_infos = (List *) funcctx->user_fctx;
1548
1549 if (funcctx->call_cntr < list_length(table_infos))
1550 {
1553 Publication *pub;
1555 Oid relid = table_info->relid;
1558 bool nulls[NUM_PUBLICATION_TABLES_ELEM] = {0};
1559
1560 /*
1561 * Form tuple with appropriate data.
1562 */
1563
1564 pub = GetPublication(table_info->pubid);
1565
1566 values[0] = ObjectIdGetDatum(pub->oid);
1567 values[1] = ObjectIdGetDatum(relid);
1568
1569 /*
1570 * We don't consider row filters or column lists for FOR ALL TABLES or
1571 * FOR TABLES IN SCHEMA publications.
1572 */
1573 if (!pub->alltables &&
1576 ObjectIdGetDatum(pub->oid)))
1578 ObjectIdGetDatum(relid),
1579 ObjectIdGetDatum(pub->oid));
1580
1582 {
1583 /* Lookup the column list attribute. */
1586 &(nulls[2]));
1587
1588 /* Null indicates no filter. */
1591 &(nulls[3]));
1592 }
1593 else
1594 {
1595 nulls[2] = true;
1596 nulls[3] = true;
1597 }
1598
1599 /* Show all columns when the column list is not specified. */
1600 if (nulls[2])
1601 {
1602 Relation rel = table_open(relid, AccessShareLock);
1603 int nattnums = 0;
1604 int16 *attnums;
1605 TupleDesc desc = RelationGetDescr(rel);
1606 int i;
1607
1608 attnums = palloc_array(int16, desc->natts);
1609
1610 for (i = 0; i < desc->natts; i++)
1611 {
1612 Form_pg_attribute att = TupleDescAttr(desc, i);
1613
1614 if (att->attisdropped)
1615 continue;
1616
1617 if (att->attgenerated)
1618 {
1619 /* We only support replication of STORED generated cols. */
1620 if (att->attgenerated != ATTRIBUTE_GENERATED_STORED)
1621 continue;
1622
1623 /*
1624 * User hasn't requested to replicate STORED generated
1625 * cols.
1626 */
1628 continue;
1629 }
1630
1631 attnums[nattnums++] = att->attnum;
1632 }
1633
1634 if (nattnums > 0)
1635 {
1636 values[2] = PointerGetDatum(buildint2vector(attnums, nattnums));
1637 nulls[2] = false;
1638 }
1639
1641 }
1642
1643 rettuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
1644
1646 }
1647
1649}
1650
1651Datum
1653{
1654 /*
1655 * Get information for all tables in the given publications.
1656 * filter_by_relid is false so all tables are returned; pub_missing_ok is
1657 * false for backward compatibility.
1658 */
1660 InvalidOid, false, false);
1661}
1662
1663Datum
1665{
1666 /*
1667 * Get information for the specified table in the given publications. The
1668 * SQL-level function is declared STRICT, so target_relid is guaranteed to
1669 * be non-NULL here.
1670 */
1672 PG_GETARG_OID(1), true, true);
1673}
1674
1675/*
1676 * Returns Oids of sequences in a publication.
1677 */
1678Datum
1680{
1682 List *sequences = NIL;
1683
1684 /* stuff done only on the first call of the function */
1685 if (SRF_IS_FIRSTCALL())
1686 {
1687 char *pubname = text_to_cstring(PG_GETARG_TEXT_PP(0));
1688 Publication *publication;
1689 MemoryContext oldcontext;
1690
1691 /* create a function context for cross-call persistence */
1693
1694 /* switch to memory context appropriate for multiple function calls */
1695 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1696
1697 publication = GetPublicationByName(pubname, false);
1698
1699 if (publication->allsequences)
1702 false);
1703
1704 funcctx->user_fctx = sequences;
1705
1706 MemoryContextSwitchTo(oldcontext);
1707 }
1708
1709 /* stuff done on every call of the function */
1711 sequences = (List *) funcctx->user_fctx;
1712
1713 if (funcctx->call_cntr < list_length(sequences))
1714 {
1715 Oid relid = list_nth_oid(sequences, funcctx->call_cntr);
1716
1718 }
1719
1721}
#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:2220
AttrNumber get_attnum(Oid relid, const char *attname)
Definition lsyscache.c:977
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2196
Oid get_publication_oid(const char *pubname, bool missing_ok)
Definition lsyscache.c:3845
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2145
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3561
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
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
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