/* Records association between publication and published table */ typedefstruct
{
Oid relid; /* OID of published table */
Oid pubid; /* OID of publication that publishes this
* table. */
} published_rel;
/* *Checkifrelationcanbeingivenpublicationandthrowsappropriate *errorifnot.
*/ staticvoid
check_publication_add_relation(Relation targetrel)
{ /* Must be a regular or partitioned table */ if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot add relation \"%s\" to publication",
RelationGetRelationName(targetrel)),
errdetail_relkind_not_supported(RelationGetForm(targetrel)->relkind)));
/* Can't be system table */ if (IsCatalogRelation(targetrel))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot add relation \"%s\" to publication",
RelationGetRelationName(targetrel)),
errdetail("This operation is not supported for system tables.")));
/* UNLOGGED and TEMP relations cannot be part of publication. */ if (targetrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot add relation \"%s\" to publication",
RelationGetRelationName(targetrel)),
errdetail("This operation is not supported for temporary tables."))); elseif (targetrel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot add relation \"%s\" to publication",
RelationGetRelationName(targetrel)),
errdetail("This operation is not supported for unlogged tables.")));
}
/* *Checkifschemacanbeingivenpublicationandthrowappropriateerrorif *not.
*/ staticvoid
check_publication_add_schema(Oid schemaid)
{ /* Can't be system namespace */ if (IsCatalogNamespace(schemaid) || IsToastNamespace(schemaid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot add schema \"%s\" to publication",
get_namespace_name(schemaid)),
errdetail("This operation is not supported for system schemas.")));
/* Can't be temporary namespace */ if (isAnyTempNamespace(schemaid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot add schema \"%s\" to publication",
get_namespace_name(schemaid)),
errdetail("Temporary schemas cannot be replicated.")));
}
cftuple = SearchSysCache2(PUBLICATIONRELMAP,
ObjectIdGetDatum(relid),
ObjectIdGetDatum(pub->oid)); if (HeapTupleIsValid(cftuple))
{
Datum cfdatum; bool isnull;
/* Lookup the column list attribute. */
cfdatum = SysCacheGetAttr(PUBLICATIONRELMAP, cftuple,
Anum_pg_publication_rel_prattrs, &isnull);
/* Was a column list found? */ if (!isnull)
{ /* Build the column list bitmap in the given memory context. */ if (cols)
*cols = pub_collist_to_bitmapset(*cols, cfdatum, mcxt);
found = true;
}
ReleaseSysCache(cftuple);
}
return found;
}
/* *Getstherelationsbasedonthepublicationpartitionoptionforaspecified *relation.
*/
List *
GetPubPartitionOptionRelations(List *result, PublicationPartOpt pub_partopt,
Oid relid)
{ if (get_rel_relkind(relid) == RELKIND_PARTITIONED_TABLE &&
pub_partopt != PUBLICATION_PART_ROOT)
{
List *all_parts = find_all_inheritors(relid, NoLock,
NULL);
if (pub_partopt == PUBLICATION_PART_ALL)
result = list_concat(result, all_parts); elseif (pub_partopt == PUBLICATION_PART_LEAF)
{
ListCell *lc;
foreach(lc, all_parts)
{
Oid partOid = lfirst_oid(lc);
if (get_rel_relkind(partOid) != RELKIND_PARTITIONED_TABLE)
result = lappend_oid(result, partOid);
}
} else
Assert(false);
} else
result = lappend_oid(result, relid);
return result;
}
/* *Returnstherelidofthetopmostancestorthatispublishedviathis *publicationifanyandsetitsancestorleveltoancestor_level, *otherwisereturnsInvalidOid. * *Theancestor_levelvalueallowsustocomparetheresultsformultiple *publications,anddecidewhichvalueishigherup. * *Notethatthelistofancestorsshouldbeorderedsuchthatthetopmost *ancestorisattheendofthelist.
*/
Oid
GetTopMostAncestorInPublication(Oid puboid, List *ancestors, int *ancestor_level)
{
ListCell *lc;
Oid topmost_relid = InvalidOid; int level = 0;
/* *Findthe"topmost"ancestorthatisinthispublication.
*/
foreach(lc, ancestors)
{
Oid ancestor = lfirst_oid(lc);
List *apubids = GetRelationPublications(ancestor);
List *aschemaPubids = NIL;
level++;
if (list_member_oid(apubids, puboid))
{
topmost_relid = ancestor;
if (ancestor_level)
*ancestor_level = level;
} else
{
aschemaPubids = GetSchemaPublications(get_rel_namespace(ancestor)); if (list_member_oid(aschemaPubids, puboid))
{
topmost_relid = ancestor;
if (ancestor_level)
*ancestor_level = level;
}
}
list_free(apubids);
list_free(aschemaPubids);
}
return topmost_relid;
}
/* *attnumstoint2vector *ConvertaBitmapsetofAttrNumbersintoanint2vector. * *AttrNumbernumbersare0-based,i.e.,notoffsetby *FirstLowInvalidHeapAttributeNumber.
*/ static int2vector *
attnumstoint2vector(Bitmapset *attrs)
{
int2vector *result; int n = bms_num_members(attrs); int i = -1; int j = 0;
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("relation \"%s\" is already member of publication \"%s\"",
RelationGetRelationName(targetrel), pub->name)));
}
check_publication_add_relation(targetrel);
/* Validate and translate column names into a Bitmapset of attnums. */
attnums = pub_collist_validate(pri->relation, pri->columns);
/* Form a tuple. */
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
/* Insert tuple into catalog. */
CatalogTupleInsert(rel, tup);
heap_freetuple(tup);
/* Register dependencies as needed */
ObjectAddressSet(myself, PublicationRelRelationId, pubreloid);
/* Add dependency on the publication */
ObjectAddressSet(referenced, PublicationRelationId, pubid);
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
/* Add dependency on the relation */
ObjectAddressSet(referenced, RelationRelationId, relid);
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
/* Add dependency on the objects mentioned in the qualifications */ if (pri->whereClause)
recordDependencyOnSingleRelExpr(&myself, pri->whereClause, relid,
DEPENDENCY_NORMAL, DEPENDENCY_NORMAL, false);
/* Add dependency on the columns, if any are listed */
i = -1; while ((i = bms_next_member(attnums, i)) >= 0)
{
ObjectAddressSubSet(referenced, RelationRelationId, relid, i);
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* Close the table. */
table_close(rel, RowExclusiveLock);
if (attnum == InvalidAttrNumber)
ereport(ERROR,
errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
colname, RelationGetRelationName(targetrel)));
if (!AttrNumberIsForUserDefinedAttr(attnum))
ereport(ERROR,
errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("cannot use system column \"%s\" in publication column list",
colname));
if (TupleDescAttr(tupdesc, attnum - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
ereport(ERROR,
errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("cannot use virtual generated column \"%s\" in publication column list",
colname));
if (bms_is_member(attnum, set))
ereport(ERROR,
errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("duplicate column \"%s\" in publication column list",
colname));
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("schema \"%s\" is already member of publication \"%s\"",
get_namespace_name(schemaid), pub->name)));
}
check_publication_add_schema(schemaid);
/* Form a tuple */
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
/* Gets list of publication oids for a relation */
List *
GetRelationPublications(Oid relid)
{
List *result = NIL;
CatCList *pubrellist; int i;
/* Find all publications associated with the relation. */
pubrellist = SearchSysCacheList1(PUBLICATIONRELMAP,
ObjectIdGetDatum(relid)); for (i = 0; i < pubrellist->n_members; i++)
{
HeapTuple tup = &pubrellist->members[i]->tuple;
Oid pubid = ((Form_pg_publication_rel) GETSTRUCT(tup))->prpubid;
/* *Getsthelistofpublicationoidsassociatedwithaspecifiedschema.
*/
List *
GetSchemaPublications(Oid schemaid)
{
List *result = NIL;
CatCList *pubschlist; int i;
/* Find all publications associated with the schema */
pubschlist = SearchSysCacheList1(PUBLICATIONNAMESPACEMAP,
ObjectIdGetDatum(schemaid)); for (i = 0; i < pubschlist->n_members; i++)
{
HeapTuple tup = &pubschlist->members[i]->tuple;
Oid pubid = ((Form_pg_publication_namespace) GETSTRUCT(tup))->pnpubid;
/* get all the relations present in the specified schema */
scan = table_beginscan_catalog(classRel, 1, key); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
Oid relid = relForm->oid; char relkind;
if (!is_publishable_class(relid, relForm)) continue;
relkind = get_rel_relkind(relid); if (relkind == RELKIND_RELATION)
result = lappend_oid(result, relid); elseif (relkind == RELKIND_PARTITIONED_TABLE)
{
List *partitionrels = NIL;
/* *Getinformationofthetablesinthegivenpublicationarray. * *Returnspubid,relid,columnlist,rowfilterforeachtable.
*/
Datum
pg_get_publication_tables(PG_FUNCTION_ARGS)
{ #define NUM_PUBLICATION_TABLES_ELEM 4
FuncCallContext *funcctx;
List *table_infos = NIL;
/* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL())
{
TupleDesc tupdesc;
MemoryContext oldcontext;
ArrayType *arr;
Datum *elems; int nelems,
i; bool viaroot = false;
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
/* switch to memory context appropriate for multiple function calls */
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/* Show all columns when the column list is not specified. */ if (nulls[2])
{
Relation rel = table_open(relid, AccessShareLock); int nattnums = 0;
int16 *attnums;
TupleDesc desc = RelationGetDescr(rel); int i;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.