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