PostgreSQL Source Code git master
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-2025, 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 /* Must be a regular or partitioned table */
59 if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
60 RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
62 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
63 errmsg("cannot add relation \"%s\" to publication",
64 RelationGetRelationName(targetrel)),
66
67 /* Can't be system table */
68 if (IsCatalogRelation(targetrel))
70 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
71 errmsg("cannot add relation \"%s\" to publication",
72 RelationGetRelationName(targetrel)),
73 errdetail("This operation is not supported for system tables.")));
74
75 /* UNLOGGED and TEMP relations cannot be part of publication. */
76 if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
78 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
79 errmsg("cannot add relation \"%s\" to publication",
80 RelationGetRelationName(targetrel)),
81 errdetail("This operation is not supported for temporary tables.")));
82 else if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
84 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
85 errmsg("cannot add relation \"%s\" to publication",
86 RelationGetRelationName(targetrel)),
87 errdetail("This operation is not supported for unlogged tables.")));
88}
89
90/*
91 * Check if schema can be in given publication and throw appropriate error if
92 * not.
93 */
94static void
96{
97 /* Can't be system namespace */
98 if (IsCatalogNamespace(schemaid) || IsToastNamespace(schemaid))
100 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
101 errmsg("cannot add schema \"%s\" to publication",
102 get_namespace_name(schemaid)),
103 errdetail("This operation is not supported for system schemas.")));
104
105 /* Can't be temporary namespace */
106 if (isAnyTempNamespace(schemaid))
108 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
109 errmsg("cannot add schema \"%s\" to publication",
110 get_namespace_name(schemaid)),
111 errdetail("Temporary schemas cannot be replicated.")));
112}
113
114/*
115 * Returns if relation represented by oid and Form_pg_class entry
116 * is publishable.
117 *
118 * Does same checks as check_publication_add_relation() above, but does not
119 * need relation to be opened and also does not throw errors.
120 *
121 * XXX This also excludes all tables with relid < FirstNormalObjectId,
122 * ie all tables created during initdb. This mainly affects the preinstalled
123 * information_schema. IsCatalogRelationOid() only excludes tables with
124 * relid < FirstUnpinnedObjectId, making that test rather redundant,
125 * but really we should get rid of the FirstNormalObjectId test not
126 * IsCatalogRelationOid. We can't do so today because we don't want
127 * information_schema tables to be considered publishable; but this test
128 * is really inadequate for that, since the information_schema could be
129 * dropped and reloaded and then it'll be considered publishable. The best
130 * long-term solution may be to add a "relispublishable" bool to pg_class,
131 * and depend on that instead of OID checks.
132 */
133static bool
135{
136 return (reltuple->relkind == RELKIND_RELATION ||
137 reltuple->relkind == RELKIND_PARTITIONED_TABLE) &&
138 !IsCatalogRelationOid(relid) &&
139 reltuple->relpersistence == RELPERSISTENCE_PERMANENT &&
140 relid >= FirstNormalObjectId;
141}
142
143/*
144 * Another variant of is_publishable_class(), taking a Relation.
145 */
146bool
148{
150}
151
152/*
153 * SQL-callable variant of the above
154 *
155 * This returns null when the relation does not exist. This is intended to be
156 * used for example in psql to avoid gratuitous errors when there are
157 * concurrent catalog changes.
158 */
159Datum
161{
162 Oid relid = PG_GETARG_OID(0);
163 HeapTuple tuple;
164 bool result;
165
166 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
167 if (!HeapTupleIsValid(tuple))
169 result = is_publishable_class(relid, (Form_pg_class) GETSTRUCT(tuple));
170 ReleaseSysCache(tuple);
171 PG_RETURN_BOOL(result);
172}
173
174/*
175 * Returns true if the ancestor is in the list of published relations.
176 * Otherwise, returns false.
177 */
178static bool
180{
181 ListCell *lc;
182
183 foreach(lc, table_infos)
184 {
185 Oid relid = ((published_rel *) lfirst(lc))->relid;
186
187 if (relid == ancestor)
188 return true;
189 }
190
191 return false;
192}
193
194/*
195 * Filter out the partitions whose parent tables are also present in the list.
196 */
197static void
199{
200 ListCell *lc;
201
202 foreach(lc, table_infos)
203 {
204 bool skip = false;
205 List *ancestors = NIL;
206 ListCell *lc2;
207 published_rel *table_info = (published_rel *) lfirst(lc);
208
209 if (get_rel_relispartition(table_info->relid))
210 ancestors = get_partition_ancestors(table_info->relid);
211
212 foreach(lc2, ancestors)
213 {
214 Oid ancestor = lfirst_oid(lc2);
215
216 if (is_ancestor_member_tableinfos(ancestor, table_infos))
217 {
218 skip = true;
219 break;
220 }
221 }
222
223 if (skip)
224 table_infos = foreach_delete_current(table_infos, lc);
225 }
226}
227
228/*
229 * Returns true if any schema is associated with the publication, false if no
230 * schema is associated with the publication.
231 */
232bool
234{
235 Relation pubschsrel;
236 ScanKeyData scankey;
237 SysScanDesc scan;
238 HeapTuple tup;
239 bool result = false;
240
241 pubschsrel = table_open(PublicationNamespaceRelationId, AccessShareLock);
242 ScanKeyInit(&scankey,
243 Anum_pg_publication_namespace_pnpubid,
244 BTEqualStrategyNumber, F_OIDEQ,
245 ObjectIdGetDatum(pubid));
246
247 scan = systable_beginscan(pubschsrel,
248 PublicationNamespacePnnspidPnpubidIndexId,
249 true, NULL, 1, &scankey);
250 tup = systable_getnext(scan);
251 result = HeapTupleIsValid(tup);
252
253 systable_endscan(scan);
254 table_close(pubschsrel, AccessShareLock);
255
256 return result;
257}
258
259/*
260 * Returns true if the relation has column list associated with the
261 * publication, false otherwise.
262 *
263 * If a column list is found, the corresponding bitmap is returned through the
264 * cols parameter, if provided. The bitmap is constructed within the given
265 * memory context (mcxt).
266 */
267bool
269 Bitmapset **cols)
270{
271 HeapTuple cftuple;
272 bool found = false;
273
274 if (pub->alltables)
275 return false;
276
277 cftuple = SearchSysCache2(PUBLICATIONRELMAP,
278 ObjectIdGetDatum(relid),
279 ObjectIdGetDatum(pub->oid));
280 if (HeapTupleIsValid(cftuple))
281 {
282 Datum cfdatum;
283 bool isnull;
284
285 /* Lookup the column list attribute. */
286 cfdatum = SysCacheGetAttr(PUBLICATIONRELMAP, cftuple,
287 Anum_pg_publication_rel_prattrs, &isnull);
288
289 /* Was a column list found? */
290 if (!isnull)
291 {
292 /* Build the column list bitmap in the given memory context. */
293 if (cols)
294 *cols = pub_collist_to_bitmapset(*cols, cfdatum, mcxt);
295
296 found = true;
297 }
298
299 ReleaseSysCache(cftuple);
300 }
301
302 return found;
303}
304
305/*
306 * Gets the relations based on the publication partition option for a specified
307 * relation.
308 */
309List *
311 Oid relid)
312{
313 if (get_rel_relkind(relid) == RELKIND_PARTITIONED_TABLE &&
314 pub_partopt != PUBLICATION_PART_ROOT)
315 {
316 List *all_parts = find_all_inheritors(relid, NoLock,
317 NULL);
318
319 if (pub_partopt == PUBLICATION_PART_ALL)
320 result = list_concat(result, all_parts);
321 else if (pub_partopt == PUBLICATION_PART_LEAF)
322 {
323 ListCell *lc;
324
325 foreach(lc, all_parts)
326 {
327 Oid partOid = lfirst_oid(lc);
328
329 if (get_rel_relkind(partOid) != RELKIND_PARTITIONED_TABLE)
330 result = lappend_oid(result, partOid);
331 }
332 }
333 else
334 Assert(false);
335 }
336 else
337 result = lappend_oid(result, relid);
338
339 return result;
340}
341
342/*
343 * Returns the relid of the topmost ancestor that is published via this
344 * publication if any and set its ancestor level to ancestor_level,
345 * otherwise returns InvalidOid.
346 *
347 * The ancestor_level value allows us to compare the results for multiple
348 * publications, and decide which value is higher up.
349 *
350 * Note that the list of ancestors should be ordered such that the topmost
351 * ancestor is at the end of the list.
352 */
353Oid
354GetTopMostAncestorInPublication(Oid puboid, List *ancestors, int *ancestor_level)
355{
356 ListCell *lc;
357 Oid topmost_relid = InvalidOid;
358 int level = 0;
359
360 /*
361 * Find the "topmost" ancestor that is in this publication.
362 */
363 foreach(lc, ancestors)
364 {
365 Oid ancestor = lfirst_oid(lc);
366 List *apubids = GetRelationPublications(ancestor);
367 List *aschemaPubids = NIL;
368
369 level++;
370
371 if (list_member_oid(apubids, puboid))
372 {
373 topmost_relid = ancestor;
374
375 if (ancestor_level)
376 *ancestor_level = level;
377 }
378 else
379 {
380 aschemaPubids = GetSchemaPublications(get_rel_namespace(ancestor));
381 if (list_member_oid(aschemaPubids, puboid))
382 {
383 topmost_relid = ancestor;
384
385 if (ancestor_level)
386 *ancestor_level = level;
387 }
388 }
389
390 list_free(apubids);
391 list_free(aschemaPubids);
392 }
393
394 return topmost_relid;
395}
396
397/*
398 * attnumstoint2vector
399 * Convert a Bitmapset of AttrNumbers into an int2vector.
400 *
401 * AttrNumber numbers are 0-based, i.e., not offset by
402 * FirstLowInvalidHeapAttributeNumber.
403 */
404static int2vector *
406{
407 int2vector *result;
408 int n = bms_num_members(attrs);
409 int i = -1;
410 int j = 0;
411
412 result = buildint2vector(NULL, n);
413
414 while ((i = bms_next_member(attrs, i)) >= 0)
415 {
417
418 result->values[j++] = (int16) i;
419 }
420
421 return result;
422}
423
424/*
425 * Insert new publication / relation mapping.
426 */
429 bool if_not_exists)
430{
431 Relation rel;
432 HeapTuple tup;
433 Datum values[Natts_pg_publication_rel];
434 bool nulls[Natts_pg_publication_rel];
435 Relation targetrel = pri->relation;
436 Oid relid = RelationGetRelid(targetrel);
437 Oid pubreloid;
438 Bitmapset *attnums;
439 Publication *pub = GetPublication(pubid);
440 ObjectAddress myself,
441 referenced;
442 List *relids = NIL;
443 int i;
444
445 rel = table_open(PublicationRelRelationId, RowExclusiveLock);
446
447 /*
448 * Check for duplicates. Note that this does not really prevent
449 * duplicates, it's here just to provide nicer error message in common
450 * case. The real protection is the unique key on the catalog.
451 */
452 if (SearchSysCacheExists2(PUBLICATIONRELMAP, ObjectIdGetDatum(relid),
453 ObjectIdGetDatum(pubid)))
454 {
456
457 if (if_not_exists)
459
462 errmsg("relation \"%s\" is already member of publication \"%s\"",
463 RelationGetRelationName(targetrel), pub->name)));
464 }
465
467
468 /* Validate and translate column names into a Bitmapset of attnums. */
469 attnums = pub_collist_validate(pri->relation, pri->columns);
470
471 /* Form a tuple. */
472 memset(values, 0, sizeof(values));
473 memset(nulls, false, sizeof(nulls));
474
475 pubreloid = GetNewOidWithIndex(rel, PublicationRelObjectIndexId,
476 Anum_pg_publication_rel_oid);
477 values[Anum_pg_publication_rel_oid - 1] = ObjectIdGetDatum(pubreloid);
478 values[Anum_pg_publication_rel_prpubid - 1] =
479 ObjectIdGetDatum(pubid);
480 values[Anum_pg_publication_rel_prrelid - 1] =
481 ObjectIdGetDatum(relid);
482
483 /* Add qualifications, if available */
484 if (pri->whereClause != NULL)
485 values[Anum_pg_publication_rel_prqual - 1] = CStringGetTextDatum(nodeToString(pri->whereClause));
486 else
487 nulls[Anum_pg_publication_rel_prqual - 1] = true;
488
489 /* Add column list, if available */
490 if (pri->columns)
491 values[Anum_pg_publication_rel_prattrs - 1] = PointerGetDatum(attnumstoint2vector(attnums));
492 else
493 nulls[Anum_pg_publication_rel_prattrs - 1] = true;
494
495 tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
496
497 /* Insert tuple into catalog. */
498 CatalogTupleInsert(rel, tup);
499 heap_freetuple(tup);
500
501 /* Register dependencies as needed */
502 ObjectAddressSet(myself, PublicationRelRelationId, pubreloid);
503
504 /* Add dependency on the publication */
505 ObjectAddressSet(referenced, PublicationRelationId, pubid);
506 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
507
508 /* Add dependency on the relation */
509 ObjectAddressSet(referenced, RelationRelationId, relid);
510 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
511
512 /* Add dependency on the objects mentioned in the qualifications */
513 if (pri->whereClause)
514 recordDependencyOnSingleRelExpr(&myself, pri->whereClause, relid,
516 false);
517
518 /* Add dependency on the columns, if any are listed */
519 i = -1;
520 while ((i = bms_next_member(attnums, i)) >= 0)
521 {
522 ObjectAddressSubSet(referenced, RelationRelationId, relid, i);
523 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
524 }
525
526 /* Close the table. */
528
529 /*
530 * Invalidate relcache so that publication info is rebuilt.
531 *
532 * For the partitioned tables, we must invalidate all partitions contained
533 * in the respective partition hierarchies, not just the one explicitly
534 * mentioned in the publication. This is required because we implicitly
535 * publish the child tables when the parent table is published.
536 */
538 relid);
539
541
542 return myself;
543}
544
545/*
546 * pub_collist_validate
547 * Process and validate the 'columns' list and ensure the columns are all
548 * valid to use for a publication. Checks for and raises an ERROR for
549 * any unknown columns, system columns, duplicate columns, or virtual
550 * generated columns.
551 *
552 * Looks up each column's attnum and returns a 0-based Bitmapset of the
553 * corresponding attnums.
554 */
555Bitmapset *
557{
558 Bitmapset *set = NULL;
559 ListCell *lc;
560 TupleDesc tupdesc = RelationGetDescr(targetrel);
561
562 foreach(lc, columns)
563 {
564 char *colname = strVal(lfirst(lc));
565 AttrNumber attnum = get_attnum(RelationGetRelid(targetrel), colname);
566
569 errcode(ERRCODE_UNDEFINED_COLUMN),
570 errmsg("column \"%s\" of relation \"%s\" does not exist",
571 colname, RelationGetRelationName(targetrel)));
572
575 errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
576 errmsg("cannot use system column \"%s\" in publication column list",
577 colname));
578
579 if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
581 errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
582 errmsg("cannot use virtual generated column \"%s\" in publication column list",
583 colname));
584
585 if (bms_is_member(attnum, set))
588 errmsg("duplicate column \"%s\" in publication column list",
589 colname));
590
591 set = bms_add_member(set, attnum);
592 }
593
594 return set;
595}
596
597/*
598 * Transform a column list (represented by an array Datum) to a bitmapset.
599 *
600 * If columns isn't NULL, add the column numbers to that set.
601 *
602 * If mcxt isn't NULL, build the bitmapset in that context.
603 */
604Bitmapset *
606{
607 Bitmapset *result = columns;
608 ArrayType *arr;
609 int nelems;
610 int16 *elems;
611 MemoryContext oldcxt = NULL;
612
613 arr = DatumGetArrayTypeP(pubcols);
614 nelems = ARR_DIMS(arr)[0];
615 elems = (int16 *) ARR_DATA_PTR(arr);
616
617 /* If a memory context was specified, switch to it. */
618 if (mcxt)
619 oldcxt = MemoryContextSwitchTo(mcxt);
620
621 for (int i = 0; i < nelems; i++)
622 result = bms_add_member(result, elems[i]);
623
624 if (mcxt)
625 MemoryContextSwitchTo(oldcxt);
626
627 return result;
628}
629
630/*
631 * Returns a bitmap representing the columns of the specified table.
632 *
633 * Generated columns are included if include_gencols_type is
634 * PUBLISH_GENCOLS_STORED.
635 */
636Bitmapset *
637pub_form_cols_map(Relation relation, PublishGencolsType include_gencols_type)
638{
639 Bitmapset *result = NULL;
640 TupleDesc desc = RelationGetDescr(relation);
641
642 for (int i = 0; i < desc->natts; i++)
643 {
644 Form_pg_attribute att = TupleDescAttr(desc, i);
645
646 if (att->attisdropped)
647 continue;
648
649 if (att->attgenerated)
650 {
651 /* We only support replication of STORED generated cols. */
652 if (att->attgenerated != ATTRIBUTE_GENERATED_STORED)
653 continue;
654
655 /* User hasn't requested to replicate STORED generated cols. */
656 if (include_gencols_type != PUBLISH_GENCOLS_STORED)
657 continue;
658 }
659
660 result = bms_add_member(result, att->attnum);
661 }
662
663 return result;
664}
665
666/*
667 * Insert new publication / schema mapping.
668 */
670publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists)
671{
672 Relation rel;
673 HeapTuple tup;
674 Datum values[Natts_pg_publication_namespace];
675 bool nulls[Natts_pg_publication_namespace];
676 Oid psschid;
677 Publication *pub = GetPublication(pubid);
678 List *schemaRels = NIL;
679 ObjectAddress myself,
680 referenced;
681
682 rel = table_open(PublicationNamespaceRelationId, RowExclusiveLock);
683
684 /*
685 * Check for duplicates. Note that this does not really prevent
686 * duplicates, it's here just to provide nicer error message in common
687 * case. The real protection is the unique key on the catalog.
688 */
689 if (SearchSysCacheExists2(PUBLICATIONNAMESPACEMAP,
690 ObjectIdGetDatum(schemaid),
691 ObjectIdGetDatum(pubid)))
692 {
694
695 if (if_not_exists)
697
700 errmsg("schema \"%s\" is already member of publication \"%s\"",
701 get_namespace_name(schemaid), pub->name)));
702 }
703
705
706 /* Form a tuple */
707 memset(values, 0, sizeof(values));
708 memset(nulls, false, sizeof(nulls));
709
710 psschid = GetNewOidWithIndex(rel, PublicationNamespaceObjectIndexId,
711 Anum_pg_publication_namespace_oid);
712 values[Anum_pg_publication_namespace_oid - 1] = ObjectIdGetDatum(psschid);
713 values[Anum_pg_publication_namespace_pnpubid - 1] =
714 ObjectIdGetDatum(pubid);
715 values[Anum_pg_publication_namespace_pnnspid - 1] =
716 ObjectIdGetDatum(schemaid);
717
718 tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
719
720 /* Insert tuple into catalog */
721 CatalogTupleInsert(rel, tup);
722 heap_freetuple(tup);
723
724 ObjectAddressSet(myself, PublicationNamespaceRelationId, psschid);
725
726 /* Add dependency on the publication */
727 ObjectAddressSet(referenced, PublicationRelationId, pubid);
728 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
729
730 /* Add dependency on the schema */
731 ObjectAddressSet(referenced, NamespaceRelationId, schemaid);
732 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
733
734 /* Close the table */
736
737 /*
738 * Invalidate relcache so that publication info is rebuilt. See
739 * publication_add_relation for why we need to consider all the
740 * partitions.
741 */
742 schemaRels = GetSchemaPublicationRelations(schemaid,
744 InvalidatePublicationRels(schemaRels);
745
746 return myself;
747}
748
749/* Gets list of publication oids for a relation */
750List *
752{
753 List *result = NIL;
754 CatCList *pubrellist;
755 int i;
756
757 /* Find all publications associated with the relation. */
758 pubrellist = SearchSysCacheList1(PUBLICATIONRELMAP,
759 ObjectIdGetDatum(relid));
760 for (i = 0; i < pubrellist->n_members; i++)
761 {
762 HeapTuple tup = &pubrellist->members[i]->tuple;
763 Oid pubid = ((Form_pg_publication_rel) GETSTRUCT(tup))->prpubid;
764
765 result = lappend_oid(result, pubid);
766 }
767
768 ReleaseSysCacheList(pubrellist);
769
770 return result;
771}
772
773/*
774 * Gets list of relation oids for a publication.
775 *
776 * This should only be used FOR TABLE publications, the FOR ALL TABLES
777 * should use GetAllTablesPublicationRelations().
778 */
779List *
781{
782 List *result;
783 Relation pubrelsrel;
784 ScanKeyData scankey;
785 SysScanDesc scan;
786 HeapTuple tup;
787
788 /* Find all publications associated with the relation. */
789 pubrelsrel = table_open(PublicationRelRelationId, AccessShareLock);
790
791 ScanKeyInit(&scankey,
792 Anum_pg_publication_rel_prpubid,
793 BTEqualStrategyNumber, F_OIDEQ,
794 ObjectIdGetDatum(pubid));
795
796 scan = systable_beginscan(pubrelsrel, PublicationRelPrpubidIndexId,
797 true, NULL, 1, &scankey);
798
799 result = NIL;
800 while (HeapTupleIsValid(tup = systable_getnext(scan)))
801 {
803
804 pubrel = (Form_pg_publication_rel) GETSTRUCT(tup);
805 result = GetPubPartitionOptionRelations(result, pub_partopt,
806 pubrel->prrelid);
807 }
808
809 systable_endscan(scan);
810 table_close(pubrelsrel, AccessShareLock);
811
812 /* Now sort and de-duplicate the result list */
813 list_sort(result, list_oid_cmp);
814 list_deduplicate_oid(result);
815
816 return result;
817}
818
819/*
820 * Gets list of publication oids for publications marked as FOR ALL TABLES.
821 */
822List *
824{
825 List *result;
826 Relation rel;
827 ScanKeyData scankey;
828 SysScanDesc scan;
829 HeapTuple tup;
830
831 /* Find all publications that are marked as for all tables. */
832 rel = table_open(PublicationRelationId, AccessShareLock);
833
834 ScanKeyInit(&scankey,
835 Anum_pg_publication_puballtables,
836 BTEqualStrategyNumber, F_BOOLEQ,
837 BoolGetDatum(true));
838
839 scan = systable_beginscan(rel, InvalidOid, false,
840 NULL, 1, &scankey);
841
842 result = NIL;
843 while (HeapTupleIsValid(tup = systable_getnext(scan)))
844 {
845 Oid oid = ((Form_pg_publication) GETSTRUCT(tup))->oid;
846
847 result = lappend_oid(result, oid);
848 }
849
850 systable_endscan(scan);
852
853 return result;
854}
855
856/*
857 * Gets list of all relation published by FOR ALL TABLES publication(s).
858 *
859 * If the publication publishes partition changes via their respective root
860 * partitioned tables, we must exclude partitions in favor of including the
861 * root partitioned tables.
862 */
863List *
865{
866 Relation classRel;
867 ScanKeyData key[1];
868 TableScanDesc scan;
869 HeapTuple tuple;
870 List *result = NIL;
871
872 classRel = table_open(RelationRelationId, AccessShareLock);
873
874 ScanKeyInit(&key[0],
875 Anum_pg_class_relkind,
876 BTEqualStrategyNumber, F_CHAREQ,
877 CharGetDatum(RELKIND_RELATION));
878
879 scan = table_beginscan_catalog(classRel, 1, key);
880
881 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
882 {
883 Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
884 Oid relid = relForm->oid;
885
886 if (is_publishable_class(relid, relForm) &&
887 !(relForm->relispartition && pubviaroot))
888 result = lappend_oid(result, relid);
889 }
890
891 table_endscan(scan);
892
893 if (pubviaroot)
894 {
895 ScanKeyInit(&key[0],
896 Anum_pg_class_relkind,
897 BTEqualStrategyNumber, F_CHAREQ,
898 CharGetDatum(RELKIND_PARTITIONED_TABLE));
899
900 scan = table_beginscan_catalog(classRel, 1, key);
901
902 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
903 {
904 Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
905 Oid relid = relForm->oid;
906
907 if (is_publishable_class(relid, relForm) &&
908 !relForm->relispartition)
909 result = lappend_oid(result, relid);
910 }
911
912 table_endscan(scan);
913 }
914
915 table_close(classRel, AccessShareLock);
916 return result;
917}
918
919/*
920 * Gets the list of schema oids for a publication.
921 *
922 * This should only be used FOR TABLES IN SCHEMA publications.
923 */
924List *
926{
927 List *result = NIL;
928 Relation pubschsrel;
929 ScanKeyData scankey;
930 SysScanDesc scan;
931 HeapTuple tup;
932
933 /* Find all schemas associated with the publication */
934 pubschsrel = table_open(PublicationNamespaceRelationId, AccessShareLock);
935
936 ScanKeyInit(&scankey,
937 Anum_pg_publication_namespace_pnpubid,
938 BTEqualStrategyNumber, F_OIDEQ,
939 ObjectIdGetDatum(pubid));
940
941 scan = systable_beginscan(pubschsrel,
942 PublicationNamespacePnnspidPnpubidIndexId,
943 true, NULL, 1, &scankey);
944 while (HeapTupleIsValid(tup = systable_getnext(scan)))
945 {
947
949
950 result = lappend_oid(result, pubsch->pnnspid);
951 }
952
953 systable_endscan(scan);
954 table_close(pubschsrel, AccessShareLock);
955
956 return result;
957}
958
959/*
960 * Gets the list of publication oids associated with a specified schema.
961 */
962List *
964{
965 List *result = NIL;
966 CatCList *pubschlist;
967 int i;
968
969 /* Find all publications associated with the schema */
970 pubschlist = SearchSysCacheList1(PUBLICATIONNAMESPACEMAP,
971 ObjectIdGetDatum(schemaid));
972 for (i = 0; i < pubschlist->n_members; i++)
973 {
974 HeapTuple tup = &pubschlist->members[i]->tuple;
975 Oid pubid = ((Form_pg_publication_namespace) GETSTRUCT(tup))->pnpubid;
976
977 result = lappend_oid(result, pubid);
978 }
979
980 ReleaseSysCacheList(pubschlist);
981
982 return result;
983}
984
985/*
986 * Get the list of publishable relation oids for a specified schema.
987 */
988List *
990{
991 Relation classRel;
992 ScanKeyData key[1];
993 TableScanDesc scan;
994 HeapTuple tuple;
995 List *result = NIL;
996
997 Assert(OidIsValid(schemaid));
998
999 classRel = table_open(RelationRelationId, AccessShareLock);
1000
1001 ScanKeyInit(&key[0],
1002 Anum_pg_class_relnamespace,
1003 BTEqualStrategyNumber, F_OIDEQ,
1004 schemaid);
1005
1006 /* get all the relations present in the specified schema */
1007 scan = table_beginscan_catalog(classRel, 1, key);
1008 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1009 {
1010 Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
1011 Oid relid = relForm->oid;
1012 char relkind;
1013
1014 if (!is_publishable_class(relid, relForm))
1015 continue;
1016
1017 relkind = get_rel_relkind(relid);
1018 if (relkind == RELKIND_RELATION)
1019 result = lappend_oid(result, relid);
1020 else if (relkind == RELKIND_PARTITIONED_TABLE)
1021 {
1022 List *partitionrels = NIL;
1023
1024 /*
1025 * It is quite possible that some of the partitions are in a
1026 * different schema than the parent table, so we need to get such
1027 * partitions separately.
1028 */
1029 partitionrels = GetPubPartitionOptionRelations(partitionrels,
1030 pub_partopt,
1031 relForm->oid);
1032 result = list_concat_unique_oid(result, partitionrels);
1033 }
1034 }
1035
1036 table_endscan(scan);
1037 table_close(classRel, AccessShareLock);
1038 return result;
1039}
1040
1041/*
1042 * Gets the list of all relations published by FOR TABLES IN SCHEMA
1043 * publication.
1044 */
1045List *
1047{
1048 List *result = NIL;
1049 List *pubschemalist = GetPublicationSchemas(pubid);
1050 ListCell *cell;
1051
1052 foreach(cell, pubschemalist)
1053 {
1054 Oid schemaid = lfirst_oid(cell);
1055 List *schemaRels = NIL;
1056
1057 schemaRels = GetSchemaPublicationRelations(schemaid, pub_partopt);
1058 result = list_concat(result, schemaRels);
1059 }
1060
1061 return result;
1062}
1063
1064/*
1065 * Get publication using oid
1066 *
1067 * The Publication struct and its data are palloc'ed here.
1068 */
1071{
1072 HeapTuple tup;
1073 Publication *pub;
1074 Form_pg_publication pubform;
1075
1076 tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
1077 if (!HeapTupleIsValid(tup))
1078 elog(ERROR, "cache lookup failed for publication %u", pubid);
1079
1080 pubform = (Form_pg_publication) GETSTRUCT(tup);
1081
1082 pub = (Publication *) palloc(sizeof(Publication));
1083 pub->oid = pubid;
1084 pub->name = pstrdup(NameStr(pubform->pubname));
1085 pub->alltables = pubform->puballtables;
1086 pub->pubactions.pubinsert = pubform->pubinsert;
1087 pub->pubactions.pubupdate = pubform->pubupdate;
1088 pub->pubactions.pubdelete = pubform->pubdelete;
1089 pub->pubactions.pubtruncate = pubform->pubtruncate;
1090 pub->pubviaroot = pubform->pubviaroot;
1091 pub->pubgencols_type = pubform->pubgencols;
1092
1093 ReleaseSysCache(tup);
1094
1095 return pub;
1096}
1097
1098/*
1099 * Get Publication using name.
1100 */
1102GetPublicationByName(const char *pubname, bool missing_ok)
1103{
1104 Oid oid;
1105
1106 oid = get_publication_oid(pubname, missing_ok);
1107
1108 return OidIsValid(oid) ? GetPublication(oid) : NULL;
1109}
1110
1111/*
1112 * Get information of the tables in the given publication array.
1113 *
1114 * Returns pubid, relid, column list, row filter for each table.
1115 */
1116Datum
1118{
1119#define NUM_PUBLICATION_TABLES_ELEM 4
1120 FuncCallContext *funcctx;
1121 List *table_infos = NIL;
1122
1123 /* stuff done only on the first call of the function */
1124 if (SRF_IS_FIRSTCALL())
1125 {
1126 TupleDesc tupdesc;
1127 MemoryContext oldcontext;
1128 ArrayType *arr;
1129 Datum *elems;
1130 int nelems,
1131 i;
1132 bool viaroot = false;
1133
1134 /* create a function context for cross-call persistence */
1135 funcctx = SRF_FIRSTCALL_INIT();
1136
1137 /* switch to memory context appropriate for multiple function calls */
1138 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1139
1140 /*
1141 * Deconstruct the parameter into elements where each element is a
1142 * publication name.
1143 */
1144 arr = PG_GETARG_ARRAYTYPE_P(0);
1145 deconstruct_array_builtin(arr, TEXTOID, &elems, NULL, &nelems);
1146
1147 /* Get Oids of tables from each publication. */
1148 for (i = 0; i < nelems; i++)
1149 {
1150 Publication *pub_elem;
1151 List *pub_elem_tables = NIL;
1152 ListCell *lc;
1153
1154 pub_elem = GetPublicationByName(TextDatumGetCString(elems[i]), false);
1155
1156 /*
1157 * Publications support partitioned tables. If
1158 * publish_via_partition_root is false, all changes are replicated
1159 * using leaf partition identity and schema, so we only need
1160 * those. Otherwise, get the partitioned table itself.
1161 */
1162 if (pub_elem->alltables)
1163 pub_elem_tables = GetAllTablesPublicationRelations(pub_elem->pubviaroot);
1164 else
1165 {
1166 List *relids,
1167 *schemarelids;
1168
1169 relids = GetPublicationRelations(pub_elem->oid,
1170 pub_elem->pubviaroot ?
1173 schemarelids = GetAllSchemaPublicationRelations(pub_elem->oid,
1174 pub_elem->pubviaroot ?
1177 pub_elem_tables = list_concat_unique_oid(relids, schemarelids);
1178 }
1179
1180 /*
1181 * Record the published table and the corresponding publication so
1182 * that we can get row filters and column lists later.
1183 *
1184 * When a table is published by multiple publications, to obtain
1185 * all row filters and column lists, the structure related to this
1186 * table will be recorded multiple times.
1187 */
1188 foreach(lc, pub_elem_tables)
1189 {
1190 published_rel *table_info = (published_rel *) palloc(sizeof(published_rel));
1191
1192 table_info->relid = lfirst_oid(lc);
1193 table_info->pubid = pub_elem->oid;
1194 table_infos = lappend(table_infos, table_info);
1195 }
1196
1197 /* At least one publication is using publish_via_partition_root. */
1198 if (pub_elem->pubviaroot)
1199 viaroot = true;
1200 }
1201
1202 /*
1203 * If the publication publishes partition changes via their respective
1204 * root partitioned tables, we must exclude partitions in favor of
1205 * including the root partitioned tables. Otherwise, the function
1206 * could return both the child and parent tables which could cause
1207 * data of the child table to be double-published on the subscriber
1208 * side.
1209 */
1210 if (viaroot)
1211 filter_partitions(table_infos);
1212
1213 /* Construct a tuple descriptor for the result rows. */
1215 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "pubid",
1216 OIDOID, -1, 0);
1217 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "relid",
1218 OIDOID, -1, 0);
1219 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "attrs",
1220 INT2VECTOROID, -1, 0);
1221 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "qual",
1222 PG_NODE_TREEOID, -1, 0);
1223
1224 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
1225 funcctx->user_fctx = table_infos;
1226
1227 MemoryContextSwitchTo(oldcontext);
1228 }
1229
1230 /* stuff done on every call of the function */
1231 funcctx = SRF_PERCALL_SETUP();
1232 table_infos = (List *) funcctx->user_fctx;
1233
1234 if (funcctx->call_cntr < list_length(table_infos))
1235 {
1236 HeapTuple pubtuple = NULL;
1237 HeapTuple rettuple;
1238 Publication *pub;
1239 published_rel *table_info = (published_rel *) list_nth(table_infos, funcctx->call_cntr);
1240 Oid relid = table_info->relid;
1241 Oid schemaid = get_rel_namespace(relid);
1243 bool nulls[NUM_PUBLICATION_TABLES_ELEM] = {0};
1244
1245 /*
1246 * Form tuple with appropriate data.
1247 */
1248
1249 pub = GetPublication(table_info->pubid);
1250
1251 values[0] = ObjectIdGetDatum(pub->oid);
1252 values[1] = ObjectIdGetDatum(relid);
1253
1254 /*
1255 * We don't consider row filters or column lists for FOR ALL TABLES or
1256 * FOR TABLES IN SCHEMA publications.
1257 */
1258 if (!pub->alltables &&
1259 !SearchSysCacheExists2(PUBLICATIONNAMESPACEMAP,
1260 ObjectIdGetDatum(schemaid),
1261 ObjectIdGetDatum(pub->oid)))
1262 pubtuple = SearchSysCacheCopy2(PUBLICATIONRELMAP,
1263 ObjectIdGetDatum(relid),
1264 ObjectIdGetDatum(pub->oid));
1265
1266 if (HeapTupleIsValid(pubtuple))
1267 {
1268 /* Lookup the column list attribute. */
1269 values[2] = SysCacheGetAttr(PUBLICATIONRELMAP, pubtuple,
1270 Anum_pg_publication_rel_prattrs,
1271 &(nulls[2]));
1272
1273 /* Null indicates no filter. */
1274 values[3] = SysCacheGetAttr(PUBLICATIONRELMAP, pubtuple,
1275 Anum_pg_publication_rel_prqual,
1276 &(nulls[3]));
1277 }
1278 else
1279 {
1280 nulls[2] = true;
1281 nulls[3] = true;
1282 }
1283
1284 /* Show all columns when the column list is not specified. */
1285 if (nulls[2])
1286 {
1287 Relation rel = table_open(relid, AccessShareLock);
1288 int nattnums = 0;
1289 int16 *attnums;
1290 TupleDesc desc = RelationGetDescr(rel);
1291 int i;
1292
1293 attnums = (int16 *) palloc(desc->natts * sizeof(int16));
1294
1295 for (i = 0; i < desc->natts; i++)
1296 {
1297 Form_pg_attribute att = TupleDescAttr(desc, i);
1298
1299 if (att->attisdropped)
1300 continue;
1301
1302 if (att->attgenerated)
1303 {
1304 /* We only support replication of STORED generated cols. */
1305 if (att->attgenerated != ATTRIBUTE_GENERATED_STORED)
1306 continue;
1307
1308 /*
1309 * User hasn't requested to replicate STORED generated
1310 * cols.
1311 */
1312 if (pub->pubgencols_type != PUBLISH_GENCOLS_STORED)
1313 continue;
1314 }
1315
1316 attnums[nattnums++] = att->attnum;
1317 }
1318
1319 if (nattnums > 0)
1320 {
1321 values[2] = PointerGetDatum(buildint2vector(attnums, nattnums));
1322 nulls[2] = false;
1323 }
1324
1326 }
1327
1328 rettuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
1329
1330 SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(rettuple));
1331 }
1332
1333 SRF_RETURN_DONE(funcctx);
1334}
#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(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3697
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:1306
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:751
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:717
int16_t int16
Definition: c.h:497
#define PG_INT16_MAX
Definition: c.h:557
#define OidIsValid(objectId)
Definition: c.h:746
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:230
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:212
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:103
bool IsCatalogRelationOid(Oid relid)
Definition: catalog.c:120
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1596
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2258
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#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:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:388
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1347
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
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:75
int i
Definition: isn.c:74
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:78
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:2110
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:893
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2086
Oid get_publication_oid(const char *pubname, bool missing_ok)
Definition: lsyscache.c:3708
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:2035
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3449
char * pstrdup(const char *in)
Definition: mcxt.c:1699
void * palloc(Size size)
Definition: mcxt.c:1317
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3687
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
char * nodeToString(const void *obj)
Definition: outfuncs.c:794
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
List * get_partition_ancestors(Oid relid)
Definition: partition.c:134
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
static const struct exclude_list_item skip[]
Definition: pg_checksums.c:107
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
FormData_pg_class * Form_pg_class
Definition: pg_class.h:156
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:45
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
#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
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#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)
List * GetRelationPublications(Oid relid)
bool is_schema_publication(Oid pubid)
ObjectAddress publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists)
List * GetPublicationSchemas(Oid pubid)
ObjectAddress publication_add_relation(Oid pubid, PublicationRelInfo *pri, bool if_not_exists)
List * GetAllTablesPublications(void)
List * GetAllSchemaPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
Publication * GetPublicationByName(const char *pubname, bool missing_ok)
List * GetSchemaPublications(Oid schemaid)
Datum pg_get_publication_tables(PG_FUNCTION_ARGS)
static void check_publication_add_relation(Relation targetrel)
static void filter_partitions(List *table_infos)
Oid GetTopMostAncestorInPublication(Oid puboid, List *ancestors, int *ancestor_level)
List * GetSchemaPublicationRelations(Oid schemaid, PublicationPartOpt pub_partopt)
static bool is_publishable_class(Oid relid, Form_pg_class reltuple)
Bitmapset * pub_form_cols_map(Relation relation, PublishGencolsType include_gencols_type)
Publication * GetPublication(Oid pubid)
List * GetAllTablesPublicationRelations(bool pubviaroot)
#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)
Bitmapset * pub_collist_to_bitmapset(Bitmapset *columns, Datum pubcols, MemoryContext mcxt)
Datum pg_relation_is_publishable(PG_FUNCTION_ARGS)
bool is_publishable_relation(Relation rel)
List * GetPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
FormData_pg_publication * Form_pg_publication
PublicationPartOpt
@ PUBLICATION_PART_LEAF
@ PUBLICATION_PART_ROOT
@ PUBLICATION_PART_ALL
FormData_pg_publication_namespace * Form_pg_publication_namespace
FormData_pg_publication_rel * Form_pg_publication_rel
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
void InvalidatePublicationRels(List *relids)
#define RelationGetForm(relation)
Definition: rel.h:507
#define RelationGetRelid(relation)
Definition: rel.h:513
#define RelationGetDescr(relation)
Definition: rel.h:539
#define RelationGetRelationName(relation)
Definition: rel.h:547
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
void * user_fctx
Definition: funcapi.h:82
uint64 call_cntr
Definition: funcapi.h:65
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
TupleDesc tuple_desc
Definition: funcapi.h:112
Definition: pg_list.h:54
PublishGencolsType pubgencols_type
PublicationActions pubactions
Form_pg_class rd_rel
Definition: rel.h:111
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:180
int n_members
Definition: catcache.h:178
HeapTupleData tuple
Definition: catcache.h:123
Definition: c.h:686
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:693
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:232
#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, struct ScanKeyData *key)
Definition: tableam.c:113
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:989
#define FirstNormalObjectId
Definition: transam.h:197
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:164
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:801
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:154
#define strVal(v)
Definition: value.h:82