Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
publicationcmds.c File Reference
Include dependency graph for publicationcmds.c:

Go to the source code of this file.

Data Structures

struct  rf_context
 

Typedefs

typedef struct rf_context rf_context
 

Functions

static ListOpenTableList (List *tables)
 
static void CloseTableList (List *rels)
 
static void LockSchemaList (List *schemalist)
 
static void PublicationAddTables (Oid pubid, List *rels, bool if_not_exists, AlterPublicationStmt *stmt)
 
static void PublicationDropTables (Oid pubid, List *rels, bool missing_ok)
 
static void PublicationAddSchemas (Oid pubid, List *schemas, bool if_not_exists, AlterPublicationStmt *stmt)
 
static void PublicationDropSchemas (Oid pubid, List *schemas, bool missing_ok)
 
static char defGetGeneratedColsOption (DefElem *def)
 
static void parse_publication_options (ParseState *pstate, List *options, bool *publish_given, PublicationActions *pubactions, bool *publish_via_partition_root_given, bool *publish_via_partition_root, bool *publish_generated_columns_given, char *publish_generated_columns)
 
static void ObjectsInPublicationToOids (List *pubobjspec_list, ParseState *pstate, List **rels, List **schemas)
 
static bool contain_invalid_rfcolumn_walker (Node *node, rf_context *context)
 
bool pub_rf_contains_invalid_column (Oid pubid, Relation relation, List *ancestors, bool pubviaroot)
 
bool pub_contains_invalid_column (Oid pubid, Relation relation, List *ancestors, bool pubviaroot, char pubgencols_type, bool *invalid_column_list, bool *invalid_gen_col)
 
void InvalidatePubRelSyncCache (Oid pubid, bool puballtables)
 
static bool contain_mutable_or_user_functions_checker (Oid func_id, void *context)
 
static bool check_simple_rowfilter_expr_walker (Node *node, ParseState *pstate)
 
static bool check_simple_rowfilter_expr (Node *node, ParseState *pstate)
 
static void TransformPubWhereClauses (List *tables, const char *queryString, bool pubviaroot)
 
static void CheckPubRelationColumnList (char *pubname, List *tables, bool publish_schema, bool pubviaroot)
 
ObjectAddress CreatePublication (ParseState *pstate, CreatePublicationStmt *stmt)
 
static void AlterPublicationOptions (ParseState *pstate, AlterPublicationStmt *stmt, Relation rel, HeapTuple tup)
 
void InvalidatePublicationRels (List *relids)
 
static void AlterPublicationTables (AlterPublicationStmt *stmt, HeapTuple tup, List *tables, const char *queryString, bool publish_schema)
 
static void AlterPublicationSchemas (AlterPublicationStmt *stmt, HeapTuple tup, List *schemaidlist)
 
static void CheckAlterPublication (AlterPublicationStmt *stmt, HeapTuple tup, List *tables, List *schemaidlist)
 
void AlterPublication (ParseState *pstate, AlterPublicationStmt *stmt)
 
void RemovePublicationRelById (Oid proid)
 
void RemovePublicationById (Oid pubid)
 
void RemovePublicationSchemaById (Oid psoid)
 
static void AlterPublicationOwner_internal (Relation rel, HeapTuple tup, Oid newOwnerId)
 
ObjectAddress AlterPublicationOwner (const char *name, Oid newOwnerId)
 
void AlterPublicationOwner_oid (Oid pubid, Oid newOwnerId)
 

Typedef Documentation

◆ rf_context

typedef struct rf_context rf_context

Function Documentation

◆ AlterPublication()

void AlterPublication ( ParseState pstate,
AlterPublicationStmt stmt 
)

Definition at line 1530 of file publicationcmds.c.

1531{
1532 Relation rel;
1533 HeapTuple tup;
1534 Form_pg_publication pubform;
1535
1536 rel = table_open(PublicationRelationId, RowExclusiveLock);
1537
1538 tup = SearchSysCacheCopy1(PUBLICATIONNAME,
1539 CStringGetDatum(stmt->pubname));
1540
1541 if (!HeapTupleIsValid(tup))
1542 ereport(ERROR,
1543 (errcode(ERRCODE_UNDEFINED_OBJECT),
1544 errmsg("publication \"%s\" does not exist",
1545 stmt->pubname)));
1546
1547 pubform = (Form_pg_publication) GETSTRUCT(tup);
1548
1549 /* must be owner */
1550 if (!object_ownercheck(PublicationRelationId, pubform->oid, GetUserId()))
1552 stmt->pubname);
1553
1554 if (stmt->options)
1555 AlterPublicationOptions(pstate, stmt, rel, tup);
1556 else
1557 {
1558 List *relations = NIL;
1559 List *schemaidlist = NIL;
1560 Oid pubid = pubform->oid;
1561
1562 ObjectsInPublicationToOids(stmt->pubobjects, pstate, &relations,
1563 &schemaidlist);
1564
1565 CheckAlterPublication(stmt, tup, relations, schemaidlist);
1566
1567 heap_freetuple(tup);
1568
1569 /* Lock the publication so nobody else can do anything with it. */
1570 LockDatabaseObject(PublicationRelationId, pubid, 0,
1572
1573 /*
1574 * It is possible that by the time we acquire the lock on publication,
1575 * concurrent DDL has removed it. We can test this by checking the
1576 * existence of publication. We get the tuple again to avoid the risk
1577 * of any publication option getting changed.
1578 */
1579 tup = SearchSysCacheCopy1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
1580 if (!HeapTupleIsValid(tup))
1581 ereport(ERROR,
1582 errcode(ERRCODE_UNDEFINED_OBJECT),
1583 errmsg("publication \"%s\" does not exist",
1584 stmt->pubname));
1585
1586 AlterPublicationTables(stmt, tup, relations, pstate->p_sourcetext,
1587 schemaidlist != NIL);
1588 AlterPublicationSchemas(stmt, tup, schemaidlist);
1589 }
1590
1591 /* Cleanup. */
1592 heap_freetuple(tup);
1594}
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2652
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4088
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
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
#define stmt
Definition: indent_codes.h:59
void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1008
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid GetUserId(void)
Definition: miscinit.c:469
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2355
#define NIL
Definition: pg_list.h:68
FormData_pg_publication * Form_pg_publication
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:360
unsigned int Oid
Definition: postgres_ext.h:32
static void AlterPublicationSchemas(AlterPublicationStmt *stmt, HeapTuple tup, List *schemaidlist)
static void ObjectsInPublicationToOids(List *pubobjspec_list, ParseState *pstate, List **rels, List **schemas)
static void CheckAlterPublication(AlterPublicationStmt *stmt, HeapTuple tup, List *tables, List *schemaidlist)
static void AlterPublicationOptions(ParseState *pstate, AlterPublicationStmt *stmt, Relation rel, HeapTuple tup)
static void AlterPublicationTables(AlterPublicationStmt *stmt, HeapTuple tup, List *tables, const char *queryString, bool publish_schema)
Definition: pg_list.h:54
const char * p_sourcetext
Definition: parse_node.h:195
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References AccessExclusiveLock, aclcheck_error(), ACLCHECK_NOT_OWNER, AlterPublicationOptions(), AlterPublicationSchemas(), AlterPublicationTables(), CheckAlterPublication(), CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT(), GetUserId(), heap_freetuple(), HeapTupleIsValid, LockDatabaseObject(), NIL, object_ownercheck(), OBJECT_PUBLICATION, ObjectIdGetDatum(), ObjectsInPublicationToOids(), ParseState::p_sourcetext, RowExclusiveLock, SearchSysCacheCopy1, stmt, table_close(), and table_open().

Referenced by ProcessUtilitySlow().

◆ AlterPublicationOptions()

static void AlterPublicationOptions ( ParseState pstate,
AlterPublicationStmt stmt,
Relation  rel,
HeapTuple  tup 
)
static

Definition at line 991 of file publicationcmds.c.

993{
994 bool nulls[Natts_pg_publication];
995 bool replaces[Natts_pg_publication];
996 Datum values[Natts_pg_publication];
997 bool publish_given;
998 PublicationActions pubactions;
999 bool publish_via_partition_root_given;
1000 bool publish_via_partition_root;
1001 bool publish_generated_columns_given;
1002 char publish_generated_columns;
1003 ObjectAddress obj;
1004 Form_pg_publication pubform;
1005 List *root_relids = NIL;
1006 ListCell *lc;
1007
1008 pubform = (Form_pg_publication) GETSTRUCT(tup);
1009
1011 stmt->options,
1012 &publish_given, &pubactions,
1013 &publish_via_partition_root_given,
1014 &publish_via_partition_root,
1015 &publish_generated_columns_given,
1016 &publish_generated_columns);
1017
1018 if (pubform->puballsequences &&
1019 (publish_given || publish_via_partition_root_given ||
1020 publish_generated_columns_given))
1022 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1023 errmsg("publication parameters are not applicable to sequence synchronization and will be ignored for sequences"));
1024
1025 /*
1026 * If the publication doesn't publish changes via the root partitioned
1027 * table, the partition's row filter and column list will be used. So
1028 * disallow using WHERE clause and column lists on partitioned table in
1029 * this case.
1030 */
1031 if (!pubform->puballtables && publish_via_partition_root_given &&
1032 !publish_via_partition_root)
1033 {
1034 /*
1035 * Lock the publication so nobody else can do anything with it. This
1036 * prevents concurrent alter to add partitioned table(s) with WHERE
1037 * clause(s) and/or column lists which we don't allow when not
1038 * publishing via root.
1039 */
1040 LockDatabaseObject(PublicationRelationId, pubform->oid, 0,
1042
1043 root_relids = GetPublicationRelations(pubform->oid,
1045
1046 foreach(lc, root_relids)
1047 {
1048 Oid relid = lfirst_oid(lc);
1049 HeapTuple rftuple;
1050 char relkind;
1051 char *relname;
1052 bool has_rowfilter;
1053 bool has_collist;
1054
1055 /*
1056 * Beware: we don't have lock on the relations, so cope silently
1057 * with the cache lookups returning NULL.
1058 */
1059
1060 rftuple = SearchSysCache2(PUBLICATIONRELMAP,
1061 ObjectIdGetDatum(relid),
1062 ObjectIdGetDatum(pubform->oid));
1063 if (!HeapTupleIsValid(rftuple))
1064 continue;
1065 has_rowfilter = !heap_attisnull(rftuple, Anum_pg_publication_rel_prqual, NULL);
1066 has_collist = !heap_attisnull(rftuple, Anum_pg_publication_rel_prattrs, NULL);
1067 if (!has_rowfilter && !has_collist)
1068 {
1069 ReleaseSysCache(rftuple);
1070 continue;
1071 }
1072
1073 relkind = get_rel_relkind(relid);
1074 if (relkind != RELKIND_PARTITIONED_TABLE)
1075 {
1076 ReleaseSysCache(rftuple);
1077 continue;
1078 }
1079 relname = get_rel_name(relid);
1080 if (relname == NULL) /* table concurrently dropped */
1081 {
1082 ReleaseSysCache(rftuple);
1083 continue;
1084 }
1085
1086 if (has_rowfilter)
1087 ereport(ERROR,
1088 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1089 errmsg("cannot set parameter \"%s\" to false for publication \"%s\"",
1090 "publish_via_partition_root",
1091 stmt->pubname),
1092 errdetail("The publication contains a WHERE clause for partitioned table \"%s\", which is not allowed when \"%s\" is false.",
1093 relname, "publish_via_partition_root")));
1094 Assert(has_collist);
1095 ereport(ERROR,
1096 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1097 errmsg("cannot set parameter \"%s\" to false for publication \"%s\"",
1098 "publish_via_partition_root",
1099 stmt->pubname),
1100 errdetail("The publication contains a column list for partitioned table \"%s\", which is not allowed when \"%s\" is false.",
1101 relname, "publish_via_partition_root")));
1102 }
1103 }
1104
1105 /* Everything ok, form a new tuple. */
1106 memset(values, 0, sizeof(values));
1107 memset(nulls, false, sizeof(nulls));
1108 memset(replaces, false, sizeof(replaces));
1109
1110 if (publish_given)
1111 {
1112 values[Anum_pg_publication_pubinsert - 1] = BoolGetDatum(pubactions.pubinsert);
1113 replaces[Anum_pg_publication_pubinsert - 1] = true;
1114
1115 values[Anum_pg_publication_pubupdate - 1] = BoolGetDatum(pubactions.pubupdate);
1116 replaces[Anum_pg_publication_pubupdate - 1] = true;
1117
1118 values[Anum_pg_publication_pubdelete - 1] = BoolGetDatum(pubactions.pubdelete);
1119 replaces[Anum_pg_publication_pubdelete - 1] = true;
1120
1121 values[Anum_pg_publication_pubtruncate - 1] = BoolGetDatum(pubactions.pubtruncate);
1122 replaces[Anum_pg_publication_pubtruncate - 1] = true;
1123 }
1124
1125 if (publish_via_partition_root_given)
1126 {
1127 values[Anum_pg_publication_pubviaroot - 1] = BoolGetDatum(publish_via_partition_root);
1128 replaces[Anum_pg_publication_pubviaroot - 1] = true;
1129 }
1130
1131 if (publish_generated_columns_given)
1132 {
1133 values[Anum_pg_publication_pubgencols - 1] = CharGetDatum(publish_generated_columns);
1134 replaces[Anum_pg_publication_pubgencols - 1] = true;
1135 }
1136
1137 tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls,
1138 replaces);
1139
1140 /* Update the catalog. */
1141 CatalogTupleUpdate(rel, &tup->t_self, tup);
1142
1144
1145 pubform = (Form_pg_publication) GETSTRUCT(tup);
1146
1147 /* Invalidate the relcache. */
1148 if (pubform->puballtables)
1149 {
1151 }
1152 else
1153 {
1154 List *relids = NIL;
1155 List *schemarelids = NIL;
1156
1157 /*
1158 * For any partitioned tables contained in the publication, we must
1159 * invalidate all partitions contained in the respective partition
1160 * trees, not just those explicitly mentioned in the publication.
1161 */
1162 if (root_relids == NIL)
1163 relids = GetPublicationRelations(pubform->oid,
1165 else
1166 {
1167 /*
1168 * We already got tables explicitly mentioned in the publication.
1169 * Now get all partitions for the partitioned table in the list.
1170 */
1171 foreach(lc, root_relids)
1172 relids = GetPubPartitionOptionRelations(relids,
1174 lfirst_oid(lc));
1175 }
1176
1177 schemarelids = GetAllSchemaPublicationRelations(pubform->oid,
1179 relids = list_concat_unique_oid(relids, schemarelids);
1180
1182 }
1183
1184 ObjectAddressSet(obj, PublicationRelationId, pubform->oid);
1186 (Node *) stmt);
1187
1188 InvokeObjectPostAlterHook(PublicationRelationId, pubform->oid, 0);
1189}
static Datum values[MAXATTR]
Definition: bootstrap.c:153
int errdetail(const char *fmt,...)
Definition: elog.c:1216
#define NOTICE
Definition: elog.h:35
void EventTriggerCollectSimpleCommand(ObjectAddress address, ObjectAddress secondaryObject, Node *parsetree)
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:456
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CacheInvalidateRelcacheAll(void)
Definition: inval.c:1654
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1469
#define AccessShareLock
Definition: lockdefs.h:36
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2095
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2170
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
NameData relname
Definition: pg_class.h:38
#define lfirst_oid(lc)
Definition: pg_list.h:174
List * GetPubPartitionOptionRelations(List *result, PublicationPartOpt pub_partopt, Oid relid)
List * GetAllSchemaPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
List * GetPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
@ PUBLICATION_PART_ROOT
@ PUBLICATION_PART_ALL
static Datum BoolGetDatum(bool X)
Definition: postgres.h:112
uint64_t Datum
Definition: postgres.h:70
static Datum CharGetDatum(char X)
Definition: postgres.h:132
void InvalidatePublicationRels(List *relids)
static void parse_publication_options(ParseState *pstate, List *options, bool *publish_given, PublicationActions *pubactions, bool *publish_via_partition_root_given, bool *publish_via_partition_root, bool *publish_generated_columns_given, char *publish_generated_columns)
#define RelationGetDescr(relation)
Definition: rel.h:540
ItemPointerData t_self
Definition: htup.h:65
Definition: nodes.h:135
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:230
void CommandCounterIncrement(void)
Definition: xact.c:1100

References AccessShareLock, Assert(), BoolGetDatum(), CacheInvalidateRelcacheAll(), CatalogTupleUpdate(), CharGetDatum(), CommandCounterIncrement(), ereport, errcode(), errdetail(), errmsg(), ERROR, EventTriggerCollectSimpleCommand(), get_rel_name(), get_rel_relkind(), GetAllSchemaPublicationRelations(), GetPublicationRelations(), GetPubPartitionOptionRelations(), GETSTRUCT(), heap_attisnull(), heap_modify_tuple(), HeapTupleIsValid, InvalidatePublicationRels(), InvalidObjectAddress, InvokeObjectPostAlterHook, lfirst_oid, list_concat_unique_oid(), LockDatabaseObject(), NIL, NOTICE, ObjectAddressSet, ObjectIdGetDatum(), parse_publication_options(), PublicationActions::pubdelete, PublicationActions::pubinsert, PUBLICATION_PART_ALL, PUBLICATION_PART_ROOT, PublicationActions::pubtruncate, PublicationActions::pubupdate, RelationGetDescr, ReleaseSysCache(), relname, SearchSysCache2(), stmt, HeapTupleData::t_self, and values.

Referenced by AlterPublication().

◆ AlterPublicationOwner()

ObjectAddress AlterPublicationOwner ( const char *  name,
Oid  newOwnerId 
)

Definition at line 2098 of file publicationcmds.c.

2099{
2100 Oid pubid;
2101 HeapTuple tup;
2102 Relation rel;
2103 ObjectAddress address;
2104 Form_pg_publication pubform;
2105
2106 rel = table_open(PublicationRelationId, RowExclusiveLock);
2107
2108 tup = SearchSysCacheCopy1(PUBLICATIONNAME, CStringGetDatum(name));
2109
2110 if (!HeapTupleIsValid(tup))
2111 ereport(ERROR,
2112 (errcode(ERRCODE_UNDEFINED_OBJECT),
2113 errmsg("publication \"%s\" does not exist", name)));
2114
2115 pubform = (Form_pg_publication) GETSTRUCT(tup);
2116 pubid = pubform->oid;
2117
2118 AlterPublicationOwner_internal(rel, tup, newOwnerId);
2119
2120 ObjectAddressSet(address, PublicationRelationId, pubid);
2121
2122 heap_freetuple(tup);
2123
2125
2126 return address;
2127}
static void AlterPublicationOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
const char * name

References AlterPublicationOwner_internal(), CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, name, ObjectAddressSet, RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by ExecAlterOwnerStmt().

◆ AlterPublicationOwner_internal()

static void AlterPublicationOwner_internal ( Relation  rel,
HeapTuple  tup,
Oid  newOwnerId 
)
static

Definition at line 2043 of file publicationcmds.c.

2044{
2046
2047 form = (Form_pg_publication) GETSTRUCT(tup);
2048
2049 if (form->pubowner == newOwnerId)
2050 return;
2051
2052 if (!superuser())
2053 {
2054 AclResult aclresult;
2055
2056 /* Must be owner */
2057 if (!object_ownercheck(PublicationRelationId, form->oid, GetUserId()))
2059 NameStr(form->pubname));
2060
2061 /* Must be able to become new owner */
2062 check_can_set_role(GetUserId(), newOwnerId);
2063
2064 /* New owner must have CREATE privilege on database */
2065 aclresult = object_aclcheck(DatabaseRelationId, MyDatabaseId, newOwnerId, ACL_CREATE);
2066 if (aclresult != ACLCHECK_OK)
2069
2070 if (!superuser_arg(newOwnerId))
2071 {
2072 if (form->puballtables || form->puballsequences ||
2073 is_schema_publication(form->oid))
2074 ereport(ERROR,
2075 errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2076 errmsg("permission denied to change owner of publication \"%s\"",
2077 NameStr(form->pubname)),
2078 errhint("The owner of a FOR ALL TABLES or ALL SEQUENCES or TABLES IN SCHEMA publication must be a superuser."));
2079 }
2080 }
2081
2082 form->pubowner = newOwnerId;
2083 CatalogTupleUpdate(rel, &tup->t_self, tup);
2084
2085 /* Update owner dependency reference */
2086 changeDependencyOnOwner(PublicationRelationId,
2087 form->oid,
2088 newOwnerId);
2089
2090 InvokeObjectPostAlterHook(PublicationRelationId,
2091 form->oid, 0);
2092}
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5341
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3834
#define NameStr(name)
Definition: c.h:751
int errhint(const char *fmt,...)
Definition: elog.c:1330
Oid MyDatabaseId
Definition: globals.c:94
char * get_database_name(Oid dbid)
Definition: lsyscache.c:1259
@ OBJECT_DATABASE
Definition: parsenodes.h:2334
#define ACL_CREATE
Definition: parsenodes.h:85
bool is_schema_publication(Oid pubid)
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:316
bool superuser_arg(Oid roleid)
Definition: superuser.c:56
bool superuser(void)
Definition: superuser.c:46

References ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, CatalogTupleUpdate(), changeDependencyOnOwner(), check_can_set_role(), ereport, errcode(), errhint(), errmsg(), ERROR, get_database_name(), GETSTRUCT(), GetUserId(), InvokeObjectPostAlterHook, is_schema_publication(), MyDatabaseId, NameStr, object_aclcheck(), OBJECT_DATABASE, object_ownercheck(), OBJECT_PUBLICATION, superuser(), superuser_arg(), and HeapTupleData::t_self.

Referenced by AlterPublicationOwner(), and AlterPublicationOwner_oid().

◆ AlterPublicationOwner_oid()

void AlterPublicationOwner_oid ( Oid  pubid,
Oid  newOwnerId 
)

Definition at line 2133 of file publicationcmds.c.

2134{
2135 HeapTuple tup;
2136 Relation rel;
2137
2138 rel = table_open(PublicationRelationId, RowExclusiveLock);
2139
2140 tup = SearchSysCacheCopy1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
2141
2142 if (!HeapTupleIsValid(tup))
2143 ereport(ERROR,
2144 (errcode(ERRCODE_UNDEFINED_OBJECT),
2145 errmsg("publication with OID %u does not exist", pubid)));
2146
2147 AlterPublicationOwner_internal(rel, tup, newOwnerId);
2148
2149 heap_freetuple(tup);
2150
2152}

References AlterPublicationOwner_internal(), ereport, errcode(), errmsg(), ERROR, heap_freetuple(), HeapTupleIsValid, ObjectIdGetDatum(), RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by shdepReassignOwned_Owner().

◆ AlterPublicationSchemas()

static void AlterPublicationSchemas ( AlterPublicationStmt stmt,
HeapTuple  tup,
List schemaidlist 
)
static

Definition at line 1378 of file publicationcmds.c.

1380{
1382
1383 /*
1384 * Nothing to do if no objects, except in SET: for that it is quite
1385 * possible that user has not specified any schemas in which case we need
1386 * to remove all the existing schemas.
1387 */
1388 if (!schemaidlist && stmt->action != AP_SetObjects)
1389 return;
1390
1391 /*
1392 * Schema lock is held until the publication is altered to prevent
1393 * concurrent schema deletion.
1394 */
1395 LockSchemaList(schemaidlist);
1396 if (stmt->action == AP_AddObjects)
1397 {
1398 ListCell *lc;
1399 List *reloids;
1400
1401 reloids = GetPublicationRelations(pubform->oid, PUBLICATION_PART_ROOT);
1402
1403 foreach(lc, reloids)
1404 {
1405 HeapTuple coltuple;
1406
1407 coltuple = SearchSysCache2(PUBLICATIONRELMAP,
1409 ObjectIdGetDatum(pubform->oid));
1410
1411 if (!HeapTupleIsValid(coltuple))
1412 continue;
1413
1414 /*
1415 * Disallow adding schema if column list is already part of the
1416 * publication. See CheckPubRelationColumnList.
1417 */
1418 if (!heap_attisnull(coltuple, Anum_pg_publication_rel_prattrs, NULL))
1419 ereport(ERROR,
1420 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1421 errmsg("cannot add schema to publication \"%s\"",
1422 stmt->pubname),
1423 errdetail("Schemas cannot be added if any tables that specify a column list are already part of the publication."));
1424
1425 ReleaseSysCache(coltuple);
1426 }
1427
1428 PublicationAddSchemas(pubform->oid, schemaidlist, false, stmt);
1429 }
1430 else if (stmt->action == AP_DropObjects)
1431 PublicationDropSchemas(pubform->oid, schemaidlist, false);
1432 else /* AP_SetObjects */
1433 {
1434 List *oldschemaids = GetPublicationSchemas(pubform->oid);
1435 List *delschemas = NIL;
1436
1437 /* Identify which schemas should be dropped */
1438 delschemas = list_difference_oid(oldschemaids, schemaidlist);
1439
1440 /*
1441 * Schema lock is held until the publication is altered to prevent
1442 * concurrent schema deletion.
1443 */
1444 LockSchemaList(delschemas);
1445
1446 /* And drop them */
1447 PublicationDropSchemas(pubform->oid, delschemas, true);
1448
1449 /*
1450 * Don't bother calculating the difference for adding, we'll catch and
1451 * skip existing ones when doing catalog update.
1452 */
1453 PublicationAddSchemas(pubform->oid, schemaidlist, true, stmt);
1454 }
1455}
List * list_difference_oid(const List *list1, const List *list2)
Definition: list.c:1313
@ AP_DropObjects
Definition: parsenodes.h:4327
@ AP_SetObjects
Definition: parsenodes.h:4328
@ AP_AddObjects
Definition: parsenodes.h:4326
List * GetPublicationSchemas(Oid pubid)
static void PublicationAddSchemas(Oid pubid, List *schemas, bool if_not_exists, AlterPublicationStmt *stmt)
static void PublicationDropSchemas(Oid pubid, List *schemas, bool missing_ok)
static void LockSchemaList(List *schemalist)

References AP_AddObjects, AP_DropObjects, AP_SetObjects, ereport, errcode(), errdetail(), errmsg(), ERROR, GetPublicationRelations(), GetPublicationSchemas(), GETSTRUCT(), heap_attisnull(), HeapTupleIsValid, lfirst_oid, list_difference_oid(), LockSchemaList(), NIL, ObjectIdGetDatum(), PUBLICATION_PART_ROOT, PublicationAddSchemas(), PublicationDropSchemas(), ReleaseSysCache(), SearchSysCache2(), and stmt.

Referenced by AlterPublication().

◆ AlterPublicationTables()

static void AlterPublicationTables ( AlterPublicationStmt stmt,
HeapTuple  tup,
List tables,
const char *  queryString,
bool  publish_schema 
)
static

Definition at line 1216 of file publicationcmds.c.

1219{
1220 List *rels = NIL;
1222 Oid pubid = pubform->oid;
1223
1224 /*
1225 * Nothing to do if no objects, except in SET: for that it is quite
1226 * possible that user has not specified any tables in which case we need
1227 * to remove all the existing tables.
1228 */
1229 if (!tables && stmt->action != AP_SetObjects)
1230 return;
1231
1232 rels = OpenTableList(tables);
1233
1234 if (stmt->action == AP_AddObjects)
1235 {
1236 TransformPubWhereClauses(rels, queryString, pubform->pubviaroot);
1237
1238 publish_schema |= is_schema_publication(pubid);
1239
1240 CheckPubRelationColumnList(stmt->pubname, rels, publish_schema,
1241 pubform->pubviaroot);
1242
1243 PublicationAddTables(pubid, rels, false, stmt);
1244 }
1245 else if (stmt->action == AP_DropObjects)
1246 PublicationDropTables(pubid, rels, false);
1247 else /* AP_SetObjects */
1248 {
1249 List *oldrelids = GetPublicationRelations(pubid,
1251 List *delrels = NIL;
1252 ListCell *oldlc;
1253
1254 TransformPubWhereClauses(rels, queryString, pubform->pubviaroot);
1255
1256 CheckPubRelationColumnList(stmt->pubname, rels, publish_schema,
1257 pubform->pubviaroot);
1258
1259 /*
1260 * To recreate the relation list for the publication, look for
1261 * existing relations that do not need to be dropped.
1262 */
1263 foreach(oldlc, oldrelids)
1264 {
1265 Oid oldrelid = lfirst_oid(oldlc);
1266 ListCell *newlc;
1267 PublicationRelInfo *oldrel;
1268 bool found = false;
1269 HeapTuple rftuple;
1270 Node *oldrelwhereclause = NULL;
1271 Bitmapset *oldcolumns = NULL;
1272
1273 /* look up the cache for the old relmap */
1274 rftuple = SearchSysCache2(PUBLICATIONRELMAP,
1275 ObjectIdGetDatum(oldrelid),
1276 ObjectIdGetDatum(pubid));
1277
1278 /*
1279 * See if the existing relation currently has a WHERE clause or a
1280 * column list. We need to compare those too.
1281 */
1282 if (HeapTupleIsValid(rftuple))
1283 {
1284 bool isnull = true;
1285 Datum whereClauseDatum;
1286 Datum columnListDatum;
1287
1288 /* Load the WHERE clause for this table. */
1289 whereClauseDatum = SysCacheGetAttr(PUBLICATIONRELMAP, rftuple,
1290 Anum_pg_publication_rel_prqual,
1291 &isnull);
1292 if (!isnull)
1293 oldrelwhereclause = stringToNode(TextDatumGetCString(whereClauseDatum));
1294
1295 /* Transform the int2vector column list to a bitmap. */
1296 columnListDatum = SysCacheGetAttr(PUBLICATIONRELMAP, rftuple,
1297 Anum_pg_publication_rel_prattrs,
1298 &isnull);
1299
1300 if (!isnull)
1301 oldcolumns = pub_collist_to_bitmapset(NULL, columnListDatum, NULL);
1302
1303 ReleaseSysCache(rftuple);
1304 }
1305
1306 foreach(newlc, rels)
1307 {
1308 PublicationRelInfo *newpubrel;
1309 Oid newrelid;
1310 Bitmapset *newcolumns = NULL;
1311
1312 newpubrel = (PublicationRelInfo *) lfirst(newlc);
1313 newrelid = RelationGetRelid(newpubrel->relation);
1314
1315 /*
1316 * Validate the column list. If the column list or WHERE
1317 * clause changes, then the validation done here will be
1318 * duplicated inside PublicationAddTables(). The validation
1319 * is cheap enough that that seems harmless.
1320 */
1321 newcolumns = pub_collist_validate(newpubrel->relation,
1322 newpubrel->columns);
1323
1324 /*
1325 * Check if any of the new set of relations matches with the
1326 * existing relations in the publication. Additionally, if the
1327 * relation has an associated WHERE clause, check the WHERE
1328 * expressions also match. Same for the column list. Drop the
1329 * rest.
1330 */
1331 if (newrelid == oldrelid)
1332 {
1333 if (equal(oldrelwhereclause, newpubrel->whereClause) &&
1334 bms_equal(oldcolumns, newcolumns))
1335 {
1336 found = true;
1337 break;
1338 }
1339 }
1340 }
1341
1342 /*
1343 * Add the non-matched relations to a list so that they can be
1344 * dropped.
1345 */
1346 if (!found)
1347 {
1348 oldrel = palloc(sizeof(PublicationRelInfo));
1349 oldrel->whereClause = NULL;
1350 oldrel->columns = NIL;
1351 oldrel->relation = table_open(oldrelid,
1353 delrels = lappend(delrels, oldrel);
1354 }
1355 }
1356
1357 /* And drop them. */
1358 PublicationDropTables(pubid, delrels, true);
1359
1360 /*
1361 * Don't bother calculating the difference for adding, we'll catch and
1362 * skip existing ones when doing catalog update.
1363 */
1364 PublicationAddTables(pubid, rels, true, stmt);
1365
1366 CloseTableList(delrels);
1367 }
1368
1369 CloseTableList(rels);
1370}
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:142
#define TextDatumGetCString(d)
Definition: builtins.h:98
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
List * lappend(List *list, void *datum)
Definition: list.c:339
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
void * palloc(Size size)
Definition: mcxt.c:1365
#define lfirst(lc)
Definition: pg_list.h:172
Bitmapset * pub_collist_validate(Relation targetrel, List *columns)
Bitmapset * pub_collist_to_bitmapset(Bitmapset *columns, Datum pubcols, MemoryContext mcxt)
static void PublicationAddTables(Oid pubid, List *rels, bool if_not_exists, AlterPublicationStmt *stmt)
static void CloseTableList(List *rels)
static void PublicationDropTables(Oid pubid, List *rels, bool missing_ok)
static void TransformPubWhereClauses(List *tables, const char *queryString, bool pubviaroot)
static List * OpenTableList(List *tables)
static void CheckPubRelationColumnList(char *pubname, List *tables, bool publish_schema, bool pubviaroot)
void * stringToNode(const char *str)
Definition: read.c:90
#define RelationGetRelid(relation)
Definition: rel.h:514
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:595

References AP_AddObjects, AP_DropObjects, AP_SetObjects, bms_equal(), CheckPubRelationColumnList(), CloseTableList(), PublicationRelInfo::columns, equal(), GetPublicationRelations(), GETSTRUCT(), HeapTupleIsValid, is_schema_publication(), lappend(), lfirst, lfirst_oid, NIL, ObjectIdGetDatum(), OpenTableList(), palloc(), pub_collist_to_bitmapset(), pub_collist_validate(), PUBLICATION_PART_ROOT, PublicationAddTables(), PublicationDropTables(), PublicationRelInfo::relation, RelationGetRelid, ReleaseSysCache(), SearchSysCache2(), ShareUpdateExclusiveLock, stmt, stringToNode(), SysCacheGetAttr(), table_open(), TextDatumGetCString, TransformPubWhereClauses(), and PublicationRelInfo::whereClause.

Referenced by AlterPublication().

◆ check_simple_rowfilter_expr()

static bool check_simple_rowfilter_expr ( Node node,
ParseState pstate 
)
static

Definition at line 686 of file publicationcmds.c.

687{
688 return check_simple_rowfilter_expr_walker(node, pstate);
689}
static bool check_simple_rowfilter_expr_walker(Node *node, ParseState *pstate)

References check_simple_rowfilter_expr_walker().

Referenced by TransformPubWhereClauses().

◆ check_simple_rowfilter_expr_walker()

static bool check_simple_rowfilter_expr_walker ( Node node,
ParseState pstate 
)
static

Definition at line 579 of file publicationcmds.c.

580{
581 char *errdetail_msg = NULL;
582
583 if (node == NULL)
584 return false;
585
586 switch (nodeTag(node))
587 {
588 case T_Var:
589 /* System columns are not allowed. */
590 if (((Var *) node)->varattno < InvalidAttrNumber)
591 errdetail_msg = _("System columns are not allowed.");
592 break;
593 case T_OpExpr:
594 case T_DistinctExpr:
595 case T_NullIfExpr:
596 /* OK, except user-defined operators are not allowed. */
597 if (((OpExpr *) node)->opno >= FirstNormalObjectId)
598 errdetail_msg = _("User-defined operators are not allowed.");
599 break;
600 case T_ScalarArrayOpExpr:
601 /* OK, except user-defined operators are not allowed. */
602 if (((ScalarArrayOpExpr *) node)->opno >= FirstNormalObjectId)
603 errdetail_msg = _("User-defined operators are not allowed.");
604
605 /*
606 * We don't need to check the hashfuncid and negfuncid of
607 * ScalarArrayOpExpr as those functions are only built for a
608 * subquery.
609 */
610 break;
611 case T_RowCompareExpr:
612 {
613 ListCell *opid;
614
615 /* OK, except user-defined operators are not allowed. */
616 foreach(opid, ((RowCompareExpr *) node)->opnos)
617 {
618 if (lfirst_oid(opid) >= FirstNormalObjectId)
619 {
620 errdetail_msg = _("User-defined operators are not allowed.");
621 break;
622 }
623 }
624 }
625 break;
626 case T_Const:
627 case T_FuncExpr:
628 case T_BoolExpr:
629 case T_RelabelType:
630 case T_CollateExpr:
631 case T_CaseExpr:
632 case T_CaseTestExpr:
633 case T_ArrayExpr:
634 case T_RowExpr:
635 case T_CoalesceExpr:
636 case T_MinMaxExpr:
637 case T_XmlExpr:
638 case T_NullTest:
639 case T_BooleanTest:
640 case T_List:
641 /* OK, supported */
642 break;
643 default:
644 errdetail_msg = _("Only columns, constants, built-in operators, built-in data types, built-in collations, and immutable built-in functions are allowed.");
645 break;
646 }
647
648 /*
649 * For all the supported nodes, if we haven't already found a problem,
650 * check the types, functions, and collations used in it. We check List
651 * by walking through each element.
652 */
653 if (!errdetail_msg && !IsA(node, List))
654 {
655 if (exprType(node) >= FirstNormalObjectId)
656 errdetail_msg = _("User-defined types are not allowed.");
658 pstate))
659 errdetail_msg = _("User-defined or built-in mutable functions are not allowed.");
660 else if (exprCollation(node) >= FirstNormalObjectId ||
662 errdetail_msg = _("User-defined collations are not allowed.");
663 }
664
665 /*
666 * If we found a problem in this node, throw error now. Otherwise keep
667 * going.
668 */
669 if (errdetail_msg)
671 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
672 errmsg("invalid publication WHERE expression"),
673 errdetail_internal("%s", errdetail_msg),
674 parser_errposition(pstate, exprLocation(node))));
675
677 pstate);
678}
#define InvalidAttrNumber
Definition: attnum.h:23
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1243
#define _(x)
Definition: elog.c:91
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
Oid exprInputCollation(const Node *expr)
Definition: nodeFuncs.c:1076
bool check_functions_in_node(Node *node, check_function_callback checker, void *context)
Definition: nodeFuncs.c:1906
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:821
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1384
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define nodeTag(nodeptr)
Definition: nodes.h:139
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
static bool contain_mutable_or_user_functions_checker(Oid func_id, void *context)
Definition: primnodes.h:262
#define FirstNormalObjectId
Definition: transam.h:197

References _, check_functions_in_node(), check_simple_rowfilter_expr_walker(), contain_mutable_or_user_functions_checker(), ereport, errcode(), errdetail_internal(), errmsg(), ERROR, exprCollation(), expression_tree_walker, exprInputCollation(), exprLocation(), exprType(), FirstNormalObjectId, InvalidAttrNumber, IsA, lfirst_oid, nodeTag, and parser_errposition().

Referenced by check_simple_rowfilter_expr(), and check_simple_rowfilter_expr_walker().

◆ CheckAlterPublication()

static void CheckAlterPublication ( AlterPublicationStmt stmt,
HeapTuple  tup,
List tables,
List schemaidlist 
)
static

Definition at line 1462 of file publicationcmds.c.

1464{
1466
1467 if ((stmt->action == AP_AddObjects || stmt->action == AP_SetObjects) &&
1468 schemaidlist && !superuser())
1469 ereport(ERROR,
1470 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1471 errmsg("must be superuser to add or set schemas")));
1472
1473 /*
1474 * Check that user is allowed to manipulate the publication tables in
1475 * schema
1476 */
1477 if (schemaidlist && (pubform->puballtables || pubform->puballsequences))
1478 {
1479 if (pubform->puballtables && pubform->puballsequences)
1480 ereport(ERROR,
1481 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1482 errmsg("publication \"%s\" is defined as FOR ALL TABLES, ALL SEQUENCES",
1483 NameStr(pubform->pubname)),
1484 errdetail("Schemas cannot be added to or dropped from FOR ALL TABLES, ALL SEQUENCES publications."));
1485 else if (pubform->puballtables)
1486 ereport(ERROR,
1487 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1488 errmsg("publication \"%s\" is defined as FOR ALL TABLES",
1489 NameStr(pubform->pubname)),
1490 errdetail("Schemas cannot be added to or dropped from FOR ALL TABLES publications."));
1491 else
1492 ereport(ERROR,
1493 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1494 errmsg("publication \"%s\" is defined as FOR ALL SEQUENCES",
1495 NameStr(pubform->pubname)),
1496 errdetail("Schemas cannot be added to or dropped from FOR ALL SEQUENCES publications."));
1497 }
1498
1499 /* Check that user is allowed to manipulate the publication tables. */
1500 if (tables && (pubform->puballtables || pubform->puballsequences))
1501 {
1502 if (pubform->puballtables && pubform->puballsequences)
1503 ereport(ERROR,
1504 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1505 errmsg("publication \"%s\" is defined as FOR ALL TABLES, ALL SEQUENCES",
1506 NameStr(pubform->pubname)),
1507 errdetail("Tables or sequences cannot be added to or dropped from FOR ALL TABLES, ALL SEQUENCES publications."));
1508 else if (pubform->puballtables)
1509 ereport(ERROR,
1510 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1511 errmsg("publication \"%s\" is defined as FOR ALL TABLES",
1512 NameStr(pubform->pubname)),
1513 errdetail("Tables or sequences cannot be added to or dropped from FOR ALL TABLES publications."));
1514 else
1515 ereport(ERROR,
1516 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1517 errmsg("publication \"%s\" is defined as FOR ALL SEQUENCES",
1518 NameStr(pubform->pubname)),
1519 errdetail("Tables or sequences cannot be added to or dropped from FOR ALL SEQUENCES publications."));
1520 }
1521}

References AP_AddObjects, AP_SetObjects, ereport, errcode(), errdetail(), errmsg(), ERROR, GETSTRUCT(), NameStr, stmt, and superuser().

Referenced by AlterPublication().

◆ CheckPubRelationColumnList()

static void CheckPubRelationColumnList ( char *  pubname,
List tables,
bool  publish_schema,
bool  pubviaroot 
)
static

Definition at line 775 of file publicationcmds.c.

777{
778 ListCell *lc;
779
780 foreach(lc, tables)
781 {
783
784 if (pri->columns == NIL)
785 continue;
786
787 /*
788 * Disallow specifying column list if any schema is in the
789 * publication.
790 *
791 * XXX We could instead just forbid the case when the publication
792 * tries to publish the table with a column list and a schema for that
793 * table. However, if we do that then we need a restriction during
794 * ALTER TABLE ... SET SCHEMA to prevent such a case which doesn't
795 * seem to be a good idea.
796 */
797 if (publish_schema)
799 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
800 errmsg("cannot use column list for relation \"%s.%s\" in publication \"%s\"",
802 RelationGetRelationName(pri->relation), pubname),
803 errdetail("Column lists cannot be specified in publications containing FOR TABLES IN SCHEMA elements."));
804
805 /*
806 * If the publication doesn't publish changes via the root partitioned
807 * table, the partition's column list will be used. So disallow using
808 * a column list on the partitioned table in this case.
809 */
810 if (!pubviaroot &&
811 pri->relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
813 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
814 errmsg("cannot use column list for relation \"%s.%s\" in publication \"%s\"",
816 RelationGetRelationName(pri->relation), pubname),
817 errdetail("Column lists cannot be specified for partitioned tables when %s is false.",
818 "publish_via_partition_root")));
819 }
820}
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3533
#define RelationGetRelationName(relation)
Definition: rel.h:548
#define RelationGetNamespace(relation)
Definition: rel.h:555
Form_pg_class rd_rel
Definition: rel.h:111

References PublicationRelInfo::columns, ereport, errcode(), errdetail(), errmsg(), ERROR, get_namespace_name(), lfirst, NIL, RelationData::rd_rel, PublicationRelInfo::relation, RelationGetNamespace, and RelationGetRelationName.

Referenced by AlterPublicationTables(), and CreatePublication().

◆ CloseTableList()

static void CloseTableList ( List rels)
static

Definition at line 1858 of file publicationcmds.c.

1859{
1860 ListCell *lc;
1861
1862 foreach(lc, rels)
1863 {
1864 PublicationRelInfo *pub_rel;
1865
1866 pub_rel = (PublicationRelInfo *) lfirst(lc);
1867 table_close(pub_rel->relation, NoLock);
1868 }
1869
1870 list_free_deep(rels);
1871}
void list_free_deep(List *list)
Definition: list.c:1560
#define NoLock
Definition: lockdefs.h:34

References lfirst, list_free_deep(), NoLock, PublicationRelInfo::relation, and table_close().

Referenced by AlterPublicationTables(), and CreatePublication().

◆ contain_invalid_rfcolumn_walker()

static bool contain_invalid_rfcolumn_walker ( Node node,
rf_context context 
)
static

Definition at line 231 of file publicationcmds.c.

232{
233 if (node == NULL)
234 return false;
235
236 if (IsA(node, Var))
237 {
238 Var *var = (Var *) node;
240
241 /*
242 * If pubviaroot is true, we are validating the row filter of the
243 * parent table, but the bitmap contains the replica identity
244 * information of the child table. So, get the column number of the
245 * child table as parent and child column order could be different.
246 */
247 if (context->pubviaroot)
248 {
249 char *colname = get_attname(context->parentid, attnum, false);
250
251 attnum = get_attnum(context->relid, colname);
252 }
253
255 context->bms_replident))
256 return true;
257 }
258
260 context);
261}
int16 AttrNumber
Definition: attnum.h:21
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:951
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:920
int16 attnum
Definition: pg_attribute.h:74
static bool contain_invalid_rfcolumn_walker(Node *node, rf_context *context)
AttrNumber varattno
Definition: primnodes.h:274
Bitmapset * bms_replident
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27

References attnum, bms_is_member(), rf_context::bms_replident, contain_invalid_rfcolumn_walker(), expression_tree_walker, FirstLowInvalidHeapAttributeNumber, get_attname(), get_attnum(), IsA, rf_context::parentid, rf_context::pubviaroot, rf_context::relid, and Var::varattno.

Referenced by contain_invalid_rfcolumn_walker(), and pub_rf_contains_invalid_column().

◆ contain_mutable_or_user_functions_checker()

static bool contain_mutable_or_user_functions_checker ( Oid  func_id,
void *  context 
)
static

Definition at line 534 of file publicationcmds.c.

535{
536 return (func_volatile(func_id) != PROVOLATILE_IMMUTABLE ||
537 func_id >= FirstNormalObjectId);
538}
char func_volatile(Oid funcid)
Definition: lsyscache.c:1947

References FirstNormalObjectId, and func_volatile().

Referenced by check_simple_rowfilter_expr_walker().

◆ CreatePublication()

ObjectAddress CreatePublication ( ParseState pstate,
CreatePublicationStmt stmt 
)

Definition at line 826 of file publicationcmds.c.

827{
828 Relation rel;
829 ObjectAddress myself;
830 Oid puboid;
831 bool nulls[Natts_pg_publication];
832 Datum values[Natts_pg_publication];
833 HeapTuple tup;
834 bool publish_given;
835 PublicationActions pubactions;
836 bool publish_via_partition_root_given;
837 bool publish_via_partition_root;
838 bool publish_generated_columns_given;
839 char publish_generated_columns;
840 AclResult aclresult;
841 List *relations = NIL;
842 List *schemaidlist = NIL;
843
844 /* must have CREATE privilege on database */
845 aclresult = object_aclcheck(DatabaseRelationId, MyDatabaseId, GetUserId(), ACL_CREATE);
846 if (aclresult != ACLCHECK_OK)
849
850 /* FOR ALL TABLES and FOR ALL SEQUENCES requires superuser */
851 if (!superuser())
852 {
853 if (stmt->for_all_tables || stmt->for_all_sequences)
855 errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
856 errmsg("must be superuser to create a FOR ALL TABLES or ALL SEQUENCES publication"));
857 }
858
859 rel = table_open(PublicationRelationId, RowExclusiveLock);
860
861 /* Check if name is used */
862 puboid = GetSysCacheOid1(PUBLICATIONNAME, Anum_pg_publication_oid,
863 CStringGetDatum(stmt->pubname));
864 if (OidIsValid(puboid))
867 errmsg("publication \"%s\" already exists",
868 stmt->pubname)));
869
870 /* Form a tuple. */
871 memset(values, 0, sizeof(values));
872 memset(nulls, false, sizeof(nulls));
873
874 values[Anum_pg_publication_pubname - 1] =
876 values[Anum_pg_publication_pubowner - 1] = ObjectIdGetDatum(GetUserId());
877
879 stmt->options,
880 &publish_given, &pubactions,
881 &publish_via_partition_root_given,
882 &publish_via_partition_root,
883 &publish_generated_columns_given,
884 &publish_generated_columns);
885
886 if (stmt->for_all_sequences &&
887 (publish_given || publish_via_partition_root_given ||
888 publish_generated_columns_given))
890 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
891 errmsg("publication parameters are not applicable to sequence synchronization and will be ignored for sequences"));
892
893 puboid = GetNewOidWithIndex(rel, PublicationObjectIndexId,
894 Anum_pg_publication_oid);
895 values[Anum_pg_publication_oid - 1] = ObjectIdGetDatum(puboid);
896 values[Anum_pg_publication_puballtables - 1] =
897 BoolGetDatum(stmt->for_all_tables);
898 values[Anum_pg_publication_puballsequences - 1] =
899 BoolGetDatum(stmt->for_all_sequences);
900 values[Anum_pg_publication_pubinsert - 1] =
901 BoolGetDatum(pubactions.pubinsert);
902 values[Anum_pg_publication_pubupdate - 1] =
903 BoolGetDatum(pubactions.pubupdate);
904 values[Anum_pg_publication_pubdelete - 1] =
905 BoolGetDatum(pubactions.pubdelete);
906 values[Anum_pg_publication_pubtruncate - 1] =
907 BoolGetDatum(pubactions.pubtruncate);
908 values[Anum_pg_publication_pubviaroot - 1] =
909 BoolGetDatum(publish_via_partition_root);
910 values[Anum_pg_publication_pubgencols - 1] =
911 CharGetDatum(publish_generated_columns);
912
913 tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
914
915 /* Insert tuple into catalog. */
916 CatalogTupleInsert(rel, tup);
917 heap_freetuple(tup);
918
919 recordDependencyOnOwner(PublicationRelationId, puboid, GetUserId());
920
921 ObjectAddressSet(myself, PublicationRelationId, puboid);
922
923 /* Make the changes visible. */
925
926 /* Associate objects with the publication. */
927 if (stmt->for_all_tables)
928 {
929 /*
930 * Invalidate relcache so that publication info is rebuilt. Sequences
931 * publication doesn't require invalidation, as replica identity
932 * checks don't apply to them.
933 */
935 }
936 else if (!stmt->for_all_sequences)
937 {
938 ObjectsInPublicationToOids(stmt->pubobjects, pstate, &relations,
939 &schemaidlist);
940
941 /* FOR TABLES IN SCHEMA requires superuser */
942 if (schemaidlist != NIL && !superuser())
944 errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
945 errmsg("must be superuser to create FOR TABLES IN SCHEMA publication"));
946
947 if (relations != NIL)
948 {
949 List *rels;
950
951 rels = OpenTableList(relations);
953 publish_via_partition_root);
954
955 CheckPubRelationColumnList(stmt->pubname, rels,
956 schemaidlist != NIL,
957 publish_via_partition_root);
958
959 PublicationAddTables(puboid, rels, true, NULL);
960 CloseTableList(rels);
961 }
962
963 if (schemaidlist != NIL)
964 {
965 /*
966 * Schema lock is held until the publication is created to prevent
967 * concurrent schema deletion.
968 */
969 LockSchemaList(schemaidlist);
970 PublicationAddSchemas(puboid, schemaidlist, true, NULL);
971 }
972 }
973
975
976 InvokeObjectPostCreateHook(PublicationRelationId, puboid, 0);
977
980 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
981 errmsg("\"wal_level\" is insufficient to publish logical changes"),
982 errhint("Set \"wal_level\" to \"logical\" before creating subscriptions.")));
983
984 return myself;
985}
#define OidIsValid(objectId)
Definition: c.h:774
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:448
#define WARNING
Definition: elog.h:36
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:682
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:109
int wal_level
Definition: xlog.c:132
@ WAL_LEVEL_LOGICAL
Definition: xlog.h:76

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, BoolGetDatum(), CacheInvalidateRelcacheAll(), CatalogTupleInsert(), CharGetDatum(), CheckPubRelationColumnList(), CloseTableList(), CommandCounterIncrement(), CStringGetDatum(), DirectFunctionCall1, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errhint(), errmsg(), ERROR, get_database_name(), GetNewOidWithIndex(), GetSysCacheOid1, GetUserId(), heap_form_tuple(), heap_freetuple(), InvokeObjectPostCreateHook, LockSchemaList(), MyDatabaseId, namein(), NIL, NOTICE, object_aclcheck(), OBJECT_DATABASE, ObjectAddressSet, ObjectIdGetDatum(), ObjectsInPublicationToOids(), OidIsValid, OpenTableList(), ParseState::p_sourcetext, parse_publication_options(), PublicationActions::pubdelete, PublicationActions::pubinsert, PublicationAddSchemas(), PublicationAddTables(), PublicationActions::pubtruncate, PublicationActions::pubupdate, recordDependencyOnOwner(), RelationGetDescr, RowExclusiveLock, stmt, superuser(), table_close(), table_open(), TransformPubWhereClauses(), values, wal_level, WAL_LEVEL_LOGICAL, and WARNING.

Referenced by ProcessUtilitySlow().

◆ defGetGeneratedColsOption()

static char defGetGeneratedColsOption ( DefElem def)
static

Definition at line 2159 of file publicationcmds.c.

2160{
2161 char *sval = "";
2162
2163 /*
2164 * A parameter value is required.
2165 */
2166 if (def->arg)
2167 {
2168 sval = defGetString(def);
2169
2170 if (pg_strcasecmp(sval, "none") == 0)
2171 return PUBLISH_GENCOLS_NONE;
2172 if (pg_strcasecmp(sval, "stored") == 0)
2173 return PUBLISH_GENCOLS_STORED;
2174 }
2175
2176 ereport(ERROR,
2177 errcode(ERRCODE_SYNTAX_ERROR),
2178 errmsg("invalid value for publication parameter \"%s\": \"%s\"", def->defname, sval),
2179 errdetail("Valid values are \"%s\" and \"%s\".", "none", "stored"));
2180
2181 return PUBLISH_GENCOLS_NONE; /* keep compiler quiet */
2182}
char * defGetString(DefElem *def)
Definition: define.c:35
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
char * defname
Definition: parsenodes.h:843
Node * arg
Definition: parsenodes.h:844

References DefElem::arg, defGetString(), DefElem::defname, ereport, errcode(), errdetail(), errmsg(), ERROR, and pg_strcasecmp().

Referenced by parse_publication_options().

◆ InvalidatePublicationRels()

void InvalidatePublicationRels ( List relids)

Definition at line 1195 of file publicationcmds.c.

1196{
1197 /*
1198 * We don't want to send too many individual messages, at some point it's
1199 * cheaper to just reset whole relcache.
1200 */
1202 {
1203 ListCell *lc;
1204
1205 foreach(lc, relids)
1207 }
1208 else
1210}
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1687
static int list_length(const List *l)
Definition: pg_list.h:152
#define MAX_RELCACHE_INVAL_MSGS

References CacheInvalidateRelcacheAll(), CacheInvalidateRelcacheByRelid(), lfirst_oid, list_length(), and MAX_RELCACHE_INVAL_MSGS.

Referenced by AlterPublicationOptions(), publication_add_relation(), publication_add_schema(), RemovePublicationRelById(), and RemovePublicationSchemaById().

◆ InvalidatePubRelSyncCache()

void InvalidatePubRelSyncCache ( Oid  pubid,
bool  puballtables 
)

Definition at line 500 of file publicationcmds.c.

501{
502 if (puballtables)
503 {
505 }
506 else
507 {
508 List *relids = NIL;
509 List *schemarelids = NIL;
510
511 /*
512 * For partitioned tables, we must invalidate all partitions and
513 * itself. WAL records for INSERT/UPDATE/DELETE specify leaf tables as
514 * a target. However, WAL records for TRUNCATE specify both a root and
515 * its leaves.
516 */
517 relids = GetPublicationRelations(pubid,
519 schemarelids = GetAllSchemaPublicationRelations(pubid,
521
522 relids = list_concat_unique_oid(relids, schemarelids);
523
524 /* Invalidate the relsyncache */
525 foreach_oid(relid, relids)
527 }
528
529 return;
530}
void CacheInvalidateRelSyncAll(void)
Definition: inval.c:1720
void CacheInvalidateRelSync(Oid relid)
Definition: inval.c:1708
#define foreach_oid(var, lst)
Definition: pg_list.h:471

References CacheInvalidateRelSync(), CacheInvalidateRelSyncAll(), foreach_oid, GetAllSchemaPublicationRelations(), GetPublicationRelations(), list_concat_unique_oid(), NIL, and PUBLICATION_PART_ALL.

Referenced by AlterObjectRename_internal().

◆ LockSchemaList()

static void LockSchemaList ( List schemalist)
static

Definition at line 1878 of file publicationcmds.c.

1879{
1880 ListCell *lc;
1881
1882 foreach(lc, schemalist)
1883 {
1884 Oid schemaid = lfirst_oid(lc);
1885
1886 /* Allow query cancel in case this takes a long time */
1888 LockDatabaseObject(NamespaceRelationId, schemaid, 0, AccessShareLock);
1889
1890 /*
1891 * It is possible that by the time we acquire the lock on schema,
1892 * concurrent DDL has removed it. We can test this by checking the
1893 * existence of schema.
1894 */
1895 if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaid)))
1896 ereport(ERROR,
1897 errcode(ERRCODE_UNDEFINED_SCHEMA),
1898 errmsg("schema with OID %u does not exist", schemaid));
1899 }
1900}
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:100

References AccessShareLock, CHECK_FOR_INTERRUPTS, ereport, errcode(), errmsg(), ERROR, lfirst_oid, LockDatabaseObject(), ObjectIdGetDatum(), and SearchSysCacheExists1.

Referenced by AlterPublicationSchemas(), and CreatePublication().

◆ ObjectsInPublicationToOids()

static void ObjectsInPublicationToOids ( List pubobjspec_list,
ParseState pstate,
List **  rels,
List **  schemas 
)
static

Definition at line 178 of file publicationcmds.c.

180{
181 ListCell *cell;
182 PublicationObjSpec *pubobj;
183
184 if (!pubobjspec_list)
185 return;
186
187 foreach(cell, pubobjspec_list)
188 {
189 Oid schemaid;
190 List *search_path;
191
192 pubobj = (PublicationObjSpec *) lfirst(cell);
193
194 switch (pubobj->pubobjtype)
195 {
197 *rels = lappend(*rels, pubobj->pubtable);
198 break;
200 schemaid = get_namespace_oid(pubobj->name, false);
201
202 /* Filter out duplicates if user specifies "sch1, sch1" */
203 *schemas = list_append_unique_oid(*schemas, schemaid);
204 break;
206 search_path = fetch_search_path(false);
207 if (search_path == NIL) /* nothing valid in search_path? */
209 errcode(ERRCODE_UNDEFINED_SCHEMA),
210 errmsg("no schema has been selected for CURRENT_SCHEMA"));
211
212 schemaid = linitial_oid(search_path);
213 list_free(search_path);
214
215 /* Filter out duplicates if user specifies "sch1, sch1" */
216 *schemas = list_append_unique_oid(*schemas, schemaid);
217 break;
218 default:
219 /* shouldn't happen */
220 elog(ERROR, "invalid publication object type %d", pubobj->pubobjtype);
221 break;
222 }
223 }
224}
#define elog(elevel,...)
Definition: elog.h:226
List * list_append_unique_oid(List *list, Oid datum)
Definition: list.c:1380
void list_free(List *list)
Definition: list.c:1546
List * fetch_search_path(bool includeImplicit)
Definition: namespace.c:4889
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3605
@ PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA
Definition: parsenodes.h:4283
@ PUBLICATIONOBJ_TABLES_IN_SCHEMA
Definition: parsenodes.h:4282
@ PUBLICATIONOBJ_TABLE
Definition: parsenodes.h:4281
#define linitial_oid(l)
Definition: pg_list.h:180
PublicationObjSpecType pubobjtype
Definition: parsenodes.h:4291
PublicationTable * pubtable
Definition: parsenodes.h:4293

References elog, ereport, errcode(), errmsg(), ERROR, fetch_search_path(), get_namespace_oid(), lappend(), lfirst, linitial_oid, list_append_unique_oid(), list_free(), PublicationObjSpec::name, NIL, PUBLICATIONOBJ_TABLE, PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA, PUBLICATIONOBJ_TABLES_IN_SCHEMA, PublicationObjSpec::pubobjtype, and PublicationObjSpec::pubtable.

Referenced by AlterPublication(), and CreatePublication().

◆ OpenTableList()

static List * OpenTableList ( List tables)
static

Definition at line 1708 of file publicationcmds.c.

1709{
1710 List *relids = NIL;
1711 List *rels = NIL;
1712 ListCell *lc;
1713 List *relids_with_rf = NIL;
1714 List *relids_with_collist = NIL;
1715
1716 /*
1717 * Open, share-lock, and check all the explicitly-specified relations
1718 */
1719 foreach(lc, tables)
1720 {
1722 bool recurse = t->relation->inh;
1723 Relation rel;
1724 Oid myrelid;
1725 PublicationRelInfo *pub_rel;
1726
1727 /* Allow query cancel in case this takes a long time */
1729
1731 myrelid = RelationGetRelid(rel);
1732
1733 /*
1734 * Filter out duplicates if user specifies "foo, foo".
1735 *
1736 * Note that this algorithm is known to not be very efficient (O(N^2))
1737 * but given that it only works on list of tables given to us by user
1738 * it's deemed acceptable.
1739 */
1740 if (list_member_oid(relids, myrelid))
1741 {
1742 /* Disallow duplicate tables if there are any with row filters. */
1743 if (t->whereClause || list_member_oid(relids_with_rf, myrelid))
1744 ereport(ERROR,
1746 errmsg("conflicting or redundant WHERE clauses for table \"%s\"",
1748
1749 /* Disallow duplicate tables if there are any with column lists. */
1750 if (t->columns || list_member_oid(relids_with_collist, myrelid))
1751 ereport(ERROR,
1753 errmsg("conflicting or redundant column lists for table \"%s\"",
1755
1757 continue;
1758 }
1759
1760 pub_rel = palloc(sizeof(PublicationRelInfo));
1761 pub_rel->relation = rel;
1762 pub_rel->whereClause = t->whereClause;
1763 pub_rel->columns = t->columns;
1764 rels = lappend(rels, pub_rel);
1765 relids = lappend_oid(relids, myrelid);
1766
1767 if (t->whereClause)
1768 relids_with_rf = lappend_oid(relids_with_rf, myrelid);
1769
1770 if (t->columns)
1771 relids_with_collist = lappend_oid(relids_with_collist, myrelid);
1772
1773 /*
1774 * Add children of this rel, if requested, so that they too are added
1775 * to the publication. A partitioned table can't have any inheritance
1776 * children other than its partitions, which need not be explicitly
1777 * added to the publication.
1778 */
1779 if (recurse && rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1780 {
1781 List *children;
1782 ListCell *child;
1783
1785 NULL);
1786
1787 foreach(child, children)
1788 {
1789 Oid childrelid = lfirst_oid(child);
1790
1791 /* Allow query cancel in case this takes a long time */
1793
1794 /*
1795 * Skip duplicates if user specified both parent and child
1796 * tables.
1797 */
1798 if (list_member_oid(relids, childrelid))
1799 {
1800 /*
1801 * We don't allow to specify row filter for both parent
1802 * and child table at the same time as it is not very
1803 * clear which one should be given preference.
1804 */
1805 if (childrelid != myrelid &&
1806 (t->whereClause || list_member_oid(relids_with_rf, childrelid)))
1807 ereport(ERROR,
1809 errmsg("conflicting or redundant WHERE clauses for table \"%s\"",
1811
1812 /*
1813 * We don't allow to specify column list for both parent
1814 * and child table at the same time as it is not very
1815 * clear which one should be given preference.
1816 */
1817 if (childrelid != myrelid &&
1818 (t->columns || list_member_oid(relids_with_collist, childrelid)))
1819 ereport(ERROR,
1821 errmsg("conflicting or redundant column lists for table \"%s\"",
1823
1824 continue;
1825 }
1826
1827 /* find_all_inheritors already got lock */
1828 rel = table_open(childrelid, NoLock);
1829 pub_rel = palloc(sizeof(PublicationRelInfo));
1830 pub_rel->relation = rel;
1831 /* child inherits WHERE clause from parent */
1832 pub_rel->whereClause = t->whereClause;
1833
1834 /* child inherits column list from parent */
1835 pub_rel->columns = t->columns;
1836 rels = lappend(rels, pub_rel);
1837 relids = lappend_oid(relids, childrelid);
1838
1839 if (t->whereClause)
1840 relids_with_rf = lappend_oid(relids_with_rf, childrelid);
1841
1842 if (t->columns)
1843 relids_with_collist = lappend_oid(relids_with_collist, childrelid);
1844 }
1845 }
1846 }
1847
1848 list_free(relids);
1849 list_free(relids_with_rf);
1850
1851 return rels;
1852}
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
#define lfirst_node(type, lc)
Definition: pg_list.h:176
RangeVar * relation
Definition: parsenodes.h:4271
bool inh
Definition: primnodes.h:86
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:83

References CHECK_FOR_INTERRUPTS, PublicationRelInfo::columns, PublicationTable::columns, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, find_all_inheritors(), RangeVar::inh, lappend(), lappend_oid(), lfirst_node, lfirst_oid, list_free(), list_member_oid(), NIL, NoLock, palloc(), RelationData::rd_rel, PublicationRelInfo::relation, PublicationTable::relation, RelationGetRelationName, RelationGetRelid, ShareUpdateExclusiveLock, table_close(), table_open(), table_openrv(), PublicationRelInfo::whereClause, and PublicationTable::whereClause.

Referenced by AlterPublicationTables(), and CreatePublication().

◆ parse_publication_options()

static void parse_publication_options ( ParseState pstate,
List options,
bool *  publish_given,
PublicationActions pubactions,
bool *  publish_via_partition_root_given,
bool *  publish_via_partition_root,
bool *  publish_generated_columns_given,
char *  publish_generated_columns 
)
static

Definition at line 77 of file publicationcmds.c.

85{
86 ListCell *lc;
87
88 *publish_given = false;
89 *publish_via_partition_root_given = false;
90 *publish_generated_columns_given = false;
91
92 /* defaults */
93 pubactions->pubinsert = true;
94 pubactions->pubupdate = true;
95 pubactions->pubdelete = true;
96 pubactions->pubtruncate = true;
97 *publish_via_partition_root = false;
98 *publish_generated_columns = PUBLISH_GENCOLS_NONE;
99
100 /* Parse options */
101 foreach(lc, options)
102 {
103 DefElem *defel = (DefElem *) lfirst(lc);
104
105 if (strcmp(defel->defname, "publish") == 0)
106 {
107 char *publish;
108 List *publish_list;
109 ListCell *lc2;
110
111 if (*publish_given)
112 errorConflictingDefElem(defel, pstate);
113
114 /*
115 * If publish option was given only the explicitly listed actions
116 * should be published.
117 */
118 pubactions->pubinsert = false;
119 pubactions->pubupdate = false;
120 pubactions->pubdelete = false;
121 pubactions->pubtruncate = false;
122
123 *publish_given = true;
124 publish = defGetString(defel);
125
126 if (!SplitIdentifierString(publish, ',', &publish_list))
128 (errcode(ERRCODE_SYNTAX_ERROR),
129 errmsg("invalid list syntax in parameter \"%s\"",
130 "publish")));
131
132 /* Process the option list. */
133 foreach(lc2, publish_list)
134 {
135 char *publish_opt = (char *) lfirst(lc2);
136
137 if (strcmp(publish_opt, "insert") == 0)
138 pubactions->pubinsert = true;
139 else if (strcmp(publish_opt, "update") == 0)
140 pubactions->pubupdate = true;
141 else if (strcmp(publish_opt, "delete") == 0)
142 pubactions->pubdelete = true;
143 else if (strcmp(publish_opt, "truncate") == 0)
144 pubactions->pubtruncate = true;
145 else
147 (errcode(ERRCODE_SYNTAX_ERROR),
148 errmsg("unrecognized value for publication option \"%s\": \"%s\"",
149 "publish", publish_opt)));
150 }
151 }
152 else if (strcmp(defel->defname, "publish_via_partition_root") == 0)
153 {
154 if (*publish_via_partition_root_given)
155 errorConflictingDefElem(defel, pstate);
156 *publish_via_partition_root_given = true;
157 *publish_via_partition_root = defGetBoolean(defel);
158 }
159 else if (strcmp(defel->defname, "publish_generated_columns") == 0)
160 {
161 if (*publish_generated_columns_given)
162 errorConflictingDefElem(defel, pstate);
163 *publish_generated_columns_given = true;
164 *publish_generated_columns = defGetGeneratedColsOption(defel);
165 }
166 else
168 (errcode(ERRCODE_SYNTAX_ERROR),
169 errmsg("unrecognized publication parameter: \"%s\"", defel->defname)));
170 }
171}
bool defGetBoolean(DefElem *def)
Definition: define.c:94
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:371
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
static char defGetGeneratedColsOption(DefElem *def)
bool SplitIdentifierString(char *rawstring, char separator, List **namelist)
Definition: varlena.c:2744

References defGetBoolean(), defGetGeneratedColsOption(), defGetString(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, errorConflictingDefElem(), if(), lfirst, PublicationActions::pubdelete, PublicationActions::pubinsert, PublicationActions::pubtruncate, PublicationActions::pubupdate, and SplitIdentifierString().

Referenced by AlterPublicationOptions(), and CreatePublication().

◆ pub_contains_invalid_column()

bool pub_contains_invalid_column ( Oid  pubid,
Relation  relation,
List ancestors,
bool  pubviaroot,
char  pubgencols_type,
bool *  invalid_column_list,
bool *  invalid_gen_col 
)

Definition at line 356 of file publicationcmds.c.

360{
361 Oid relid = RelationGetRelid(relation);
362 Oid publish_as_relid = RelationGetRelid(relation);
363 Bitmapset *idattrs;
364 Bitmapset *columns = NULL;
365 TupleDesc desc = RelationGetDescr(relation);
366 Publication *pub;
367 int x;
368
369 *invalid_column_list = false;
370 *invalid_gen_col = false;
371
372 /*
373 * For a partition, if pubviaroot is true, find the topmost ancestor that
374 * is published via this publication as we need to use its column list for
375 * the changes.
376 *
377 * Note that even though the column list used is for an ancestor, the
378 * REPLICA IDENTITY used will be for the actual child table.
379 */
380 if (pubviaroot && relation->rd_rel->relispartition)
381 {
382 publish_as_relid = GetTopMostAncestorInPublication(pubid, ancestors, NULL);
383
384 if (!OidIsValid(publish_as_relid))
385 publish_as_relid = relid;
386 }
387
388 /* Fetch the column list */
389 pub = GetPublication(pubid);
390 check_and_fetch_column_list(pub, publish_as_relid, NULL, &columns);
391
392 if (relation->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
393 {
394 /* With REPLICA IDENTITY FULL, no column list is allowed. */
395 *invalid_column_list = (columns != NULL);
396
397 /*
398 * As we don't allow a column list with REPLICA IDENTITY FULL, the
399 * publish_generated_columns option must be set to stored if the table
400 * has any stored generated columns.
401 */
402 if (pubgencols_type != PUBLISH_GENCOLS_STORED &&
403 relation->rd_att->constr &&
405 *invalid_gen_col = true;
406
407 /*
408 * Virtual generated columns are currently not supported for logical
409 * replication at all.
410 */
411 if (relation->rd_att->constr &&
413 *invalid_gen_col = true;
414
415 if (*invalid_gen_col && *invalid_column_list)
416 return true;
417 }
418
419 /* Remember columns that are part of the REPLICA IDENTITY */
420 idattrs = RelationGetIndexAttrBitmap(relation,
422
423 /*
424 * Attnums in the bitmap returned by RelationGetIndexAttrBitmap are offset
425 * (to handle system columns the usual way), while column list does not
426 * use offset, so we can't do bms_is_subset(). Instead, we have to loop
427 * over the idattrs and check all of them are in the list.
428 */
429 x = -1;
430 while ((x = bms_next_member(idattrs, x)) >= 0)
431 {
433 Form_pg_attribute att = TupleDescAttr(desc, attnum - 1);
434
435 if (columns == NULL)
436 {
437 /*
438 * The publish_generated_columns option must be set to stored if
439 * the REPLICA IDENTITY contains any stored generated column.
440 */
441 if (att->attgenerated == ATTRIBUTE_GENERATED_STORED && pubgencols_type != PUBLISH_GENCOLS_STORED)
442 {
443 *invalid_gen_col = true;
444 break;
445 }
446
447 /*
448 * The equivalent setting for virtual generated columns does not
449 * exist yet.
450 */
451 if (att->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
452 {
453 *invalid_gen_col = true;
454 break;
455 }
456
457 /* Skip validating the column list since it is not defined */
458 continue;
459 }
460
461 /*
462 * If pubviaroot is true, we are validating the column list of the
463 * parent table, but the bitmap contains the replica identity
464 * information of the child table. The parent/child attnums may not
465 * match, so translate them to the parent - get the attname from the
466 * child, and look it up in the parent.
467 */
468 if (pubviaroot)
469 {
470 /* attribute name in the child table */
471 char *colname = get_attname(relid, attnum, false);
472
473 /*
474 * Determine the attnum for the attribute name in parent (we are
475 * using the column list defined on the parent).
476 */
477 attnum = get_attnum(publish_as_relid, colname);
478 }
479
480 /* replica identity column, not covered by the column list */
481 *invalid_column_list |= !bms_is_member(attnum, columns);
482
483 if (*invalid_column_list && *invalid_gen_col)
484 break;
485 }
486
487 bms_free(columns);
488 bms_free(idattrs);
489
490 return *invalid_column_list || *invalid_gen_col;
491}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
void bms_free(Bitmapset *a)
Definition: bitmapset.c:239
int x
Definition: isn.c:75
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
Oid GetTopMostAncestorInPublication(Oid puboid, List *ancestors, int *ancestor_level)
Publication * GetPublication(Oid pubid)
bool check_and_fetch_column_list(Publication *pub, Oid relid, MemoryContext mcxt, Bitmapset **cols)
Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Definition: relcache.c:5303
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:71
TupleDesc rd_att
Definition: rel.h:112
bool has_generated_virtual
Definition: tupdesc.h:47
bool has_generated_stored
Definition: tupdesc.h:46
TupleConstr * constr
Definition: tupdesc.h:141
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160

References attnum, bms_free(), bms_is_member(), bms_next_member(), check_and_fetch_column_list(), TupleDescData::constr, FirstLowInvalidHeapAttributeNumber, get_attname(), get_attnum(), GetPublication(), GetTopMostAncestorInPublication(), TupleConstr::has_generated_stored, TupleConstr::has_generated_virtual, INDEX_ATTR_BITMAP_IDENTITY_KEY, OidIsValid, RelationData::rd_att, RelationData::rd_rel, RelationGetDescr, RelationGetIndexAttrBitmap(), RelationGetRelid, TupleDescAttr(), and x.

Referenced by RelationBuildPublicationDesc().

◆ pub_rf_contains_invalid_column()

bool pub_rf_contains_invalid_column ( Oid  pubid,
Relation  relation,
List ancestors,
bool  pubviaroot 
)

Definition at line 270 of file publicationcmds.c.

272{
273 HeapTuple rftuple;
274 Oid relid = RelationGetRelid(relation);
275 Oid publish_as_relid = RelationGetRelid(relation);
276 bool result = false;
277 Datum rfdatum;
278 bool rfisnull;
279
280 /*
281 * FULL means all columns are in the REPLICA IDENTITY, so all columns are
282 * allowed in the row filter and we can skip the validation.
283 */
284 if (relation->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
285 return false;
286
287 /*
288 * For a partition, if pubviaroot is true, find the topmost ancestor that
289 * is published via this publication as we need to use its row filter
290 * expression to filter the partition's changes.
291 *
292 * Note that even though the row filter used is for an ancestor, the
293 * REPLICA IDENTITY used will be for the actual child table.
294 */
295 if (pubviaroot && relation->rd_rel->relispartition)
296 {
297 publish_as_relid
298 = GetTopMostAncestorInPublication(pubid, ancestors, NULL);
299
300 if (!OidIsValid(publish_as_relid))
301 publish_as_relid = relid;
302 }
303
304 rftuple = SearchSysCache2(PUBLICATIONRELMAP,
305 ObjectIdGetDatum(publish_as_relid),
306 ObjectIdGetDatum(pubid));
307
308 if (!HeapTupleIsValid(rftuple))
309 return false;
310
311 rfdatum = SysCacheGetAttr(PUBLICATIONRELMAP, rftuple,
312 Anum_pg_publication_rel_prqual,
313 &rfisnull);
314
315 if (!rfisnull)
316 {
317 rf_context context = {0};
318 Node *rfnode;
319 Bitmapset *bms = NULL;
320
321 context.pubviaroot = pubviaroot;
322 context.parentid = publish_as_relid;
323 context.relid = relid;
324
325 /* Remember columns that are part of the REPLICA IDENTITY */
326 bms = RelationGetIndexAttrBitmap(relation,
328
329 context.bms_replident = bms;
330 rfnode = stringToNode(TextDatumGetCString(rfdatum));
331 result = contain_invalid_rfcolumn_walker(rfnode, &context);
332 }
333
334 ReleaseSysCache(rftuple);
335
336 return result;
337}

References rf_context::bms_replident, contain_invalid_rfcolumn_walker(), GetTopMostAncestorInPublication(), HeapTupleIsValid, INDEX_ATTR_BITMAP_IDENTITY_KEY, ObjectIdGetDatum(), OidIsValid, rf_context::parentid, rf_context::pubviaroot, RelationData::rd_rel, RelationGetIndexAttrBitmap(), RelationGetRelid, ReleaseSysCache(), rf_context::relid, SearchSysCache2(), stringToNode(), SysCacheGetAttr(), and TextDatumGetCString.

Referenced by RelationBuildPublicationDesc().

◆ PublicationAddSchemas()

static void PublicationAddSchemas ( Oid  pubid,
List schemas,
bool  if_not_exists,
AlterPublicationStmt stmt 
)
static

Definition at line 1983 of file publicationcmds.c.

1985{
1986 ListCell *lc;
1987
1988 foreach(lc, schemas)
1989 {
1990 Oid schemaid = lfirst_oid(lc);
1991 ObjectAddress obj;
1992
1993 obj = publication_add_schema(pubid, schemaid, if_not_exists);
1994 if (stmt)
1995 {
1997 (Node *) stmt);
1998
1999 InvokeObjectPostCreateHook(PublicationNamespaceRelationId,
2000 obj.objectId, 0);
2001 }
2002 }
2003}
ObjectAddress publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists)

References EventTriggerCollectSimpleCommand(), InvalidObjectAddress, InvokeObjectPostCreateHook, lfirst_oid, ObjectAddress::objectId, publication_add_schema(), and stmt.

Referenced by AlterPublicationSchemas(), and CreatePublication().

◆ PublicationAddTables()

static void PublicationAddTables ( Oid  pubid,
List rels,
bool  if_not_exists,
AlterPublicationStmt stmt 
)
static

Definition at line 1906 of file publicationcmds.c.

1908{
1909 ListCell *lc;
1910
1911 foreach(lc, rels)
1912 {
1913 PublicationRelInfo *pub_rel = (PublicationRelInfo *) lfirst(lc);
1914 Relation rel = pub_rel->relation;
1915 ObjectAddress obj;
1916
1917 /* Must be owner of the table or superuser. */
1918 if (!object_ownercheck(RelationRelationId, RelationGetRelid(rel), GetUserId()))
1921
1922 obj = publication_add_relation(pubid, pub_rel, if_not_exists);
1923 if (stmt)
1924 {
1926 (Node *) stmt);
1927
1928 InvokeObjectPostCreateHook(PublicationRelRelationId,
1929 obj.objectId, 0);
1930 }
1931 }
1932}
ObjectType get_relkind_objtype(char relkind)
ObjectAddress publication_add_relation(Oid pubid, PublicationRelInfo *pri, bool if_not_exists)

References aclcheck_error(), ACLCHECK_NOT_OWNER, EventTriggerCollectSimpleCommand(), get_relkind_objtype(), GetUserId(), InvalidObjectAddress, InvokeObjectPostCreateHook, lfirst, object_ownercheck(), ObjectAddress::objectId, publication_add_relation(), RelationData::rd_rel, PublicationRelInfo::relation, RelationGetRelationName, RelationGetRelid, and stmt.

Referenced by AlterPublicationTables(), and CreatePublication().

◆ PublicationDropSchemas()

static void PublicationDropSchemas ( Oid  pubid,
List schemas,
bool  missing_ok 
)
static

Definition at line 2009 of file publicationcmds.c.

2010{
2011 ObjectAddress obj;
2012 ListCell *lc;
2013 Oid psid;
2014
2015 foreach(lc, schemas)
2016 {
2017 Oid schemaid = lfirst_oid(lc);
2018
2019 psid = GetSysCacheOid2(PUBLICATIONNAMESPACEMAP,
2020 Anum_pg_publication_namespace_oid,
2021 ObjectIdGetDatum(schemaid),
2022 ObjectIdGetDatum(pubid));
2023 if (!OidIsValid(psid))
2024 {
2025 if (missing_ok)
2026 continue;
2027
2028 ereport(ERROR,
2029 (errcode(ERRCODE_UNDEFINED_OBJECT),
2030 errmsg("tables from schema \"%s\" are not part of the publication",
2031 get_namespace_name(schemaid))));
2032 }
2033
2034 ObjectAddressSet(obj, PublicationNamespaceRelationId, psid);
2035 performDeletion(&obj, DROP_CASCADE, 0);
2036 }
2037}
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:273
@ DROP_CASCADE
Definition: parsenodes.h:2399
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:111

References DROP_CASCADE, ereport, errcode(), errmsg(), ERROR, get_namespace_name(), GetSysCacheOid2, lfirst_oid, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, and performDeletion().

Referenced by AlterPublicationSchemas().

◆ PublicationDropTables()

static void PublicationDropTables ( Oid  pubid,
List rels,
bool  missing_ok 
)
static

Definition at line 1938 of file publicationcmds.c.

1939{
1940 ObjectAddress obj;
1941 ListCell *lc;
1942 Oid prid;
1943
1944 foreach(lc, rels)
1945 {
1947 Relation rel = pubrel->relation;
1948 Oid relid = RelationGetRelid(rel);
1949
1950 if (pubrel->columns)
1951 ereport(ERROR,
1952 errcode(ERRCODE_SYNTAX_ERROR),
1953 errmsg("column list must not be specified in ALTER PUBLICATION ... DROP"));
1954
1955 prid = GetSysCacheOid2(PUBLICATIONRELMAP, Anum_pg_publication_rel_oid,
1956 ObjectIdGetDatum(relid),
1957 ObjectIdGetDatum(pubid));
1958 if (!OidIsValid(prid))
1959 {
1960 if (missing_ok)
1961 continue;
1962
1963 ereport(ERROR,
1964 (errcode(ERRCODE_UNDEFINED_OBJECT),
1965 errmsg("relation \"%s\" is not part of the publication",
1967 }
1968
1969 if (pubrel->whereClause)
1970 ereport(ERROR,
1971 (errcode(ERRCODE_SYNTAX_ERROR),
1972 errmsg("cannot use a WHERE clause when removing a table from a publication")));
1973
1974 ObjectAddressSet(obj, PublicationRelRelationId, prid);
1975 performDeletion(&obj, DROP_CASCADE, 0);
1976 }
1977}

References PublicationRelInfo::columns, DROP_CASCADE, ereport, errcode(), errmsg(), ERROR, GetSysCacheOid2, lfirst, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, performDeletion(), PublicationRelInfo::relation, RelationGetRelationName, RelationGetRelid, and PublicationRelInfo::whereClause.

Referenced by AlterPublicationTables().

◆ RemovePublicationById()

void RemovePublicationById ( Oid  pubid)

Definition at line 1641 of file publicationcmds.c.

1642{
1643 Relation rel;
1644 HeapTuple tup;
1645 Form_pg_publication pubform;
1646
1647 rel = table_open(PublicationRelationId, RowExclusiveLock);
1648
1649 tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
1650 if (!HeapTupleIsValid(tup))
1651 elog(ERROR, "cache lookup failed for publication %u", pubid);
1652
1653 pubform = (Form_pg_publication) GETSTRUCT(tup);
1654
1655 /* Invalidate relcache so that publication info is rebuilt. */
1656 if (pubform->puballtables)
1658
1659 CatalogTupleDelete(rel, &tup->t_self);
1660
1661 ReleaseSysCache(tup);
1662
1664}
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:220

References CacheInvalidateRelcacheAll(), CatalogTupleDelete(), elog, ERROR, GETSTRUCT(), HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ RemovePublicationRelById()

void RemovePublicationRelById ( Oid  proid)

Definition at line 1600 of file publicationcmds.c.

1601{
1602 Relation rel;
1603 HeapTuple tup;
1605 List *relids = NIL;
1606
1607 rel = table_open(PublicationRelRelationId, RowExclusiveLock);
1608
1609 tup = SearchSysCache1(PUBLICATIONREL, ObjectIdGetDatum(proid));
1610
1611 if (!HeapTupleIsValid(tup))
1612 elog(ERROR, "cache lookup failed for publication table %u",
1613 proid);
1614
1615 pubrel = (Form_pg_publication_rel) GETSTRUCT(tup);
1616
1617 /*
1618 * Invalidate relcache so that publication info is rebuilt.
1619 *
1620 * For the partitioned tables, we must invalidate all partitions contained
1621 * in the respective partition hierarchies, not just the one explicitly
1622 * mentioned in the publication. This is required because we implicitly
1623 * publish the child tables when the parent table is published.
1624 */
1626 pubrel->prrelid);
1627
1629
1630 CatalogTupleDelete(rel, &tup->t_self);
1631
1632 ReleaseSysCache(tup);
1633
1635}
FormData_pg_publication_rel * Form_pg_publication_rel

References CatalogTupleDelete(), elog, ERROR, GetPubPartitionOptionRelations(), GETSTRUCT(), HeapTupleIsValid, InvalidatePublicationRels(), NIL, ObjectIdGetDatum(), PUBLICATION_PART_ALL, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ RemovePublicationSchemaById()

void RemovePublicationSchemaById ( Oid  psoid)

Definition at line 1670 of file publicationcmds.c.

1671{
1672 Relation rel;
1673 HeapTuple tup;
1674 List *schemaRels = NIL;
1676
1677 rel = table_open(PublicationNamespaceRelationId, RowExclusiveLock);
1678
1679 tup = SearchSysCache1(PUBLICATIONNAMESPACE, ObjectIdGetDatum(psoid));
1680
1681 if (!HeapTupleIsValid(tup))
1682 elog(ERROR, "cache lookup failed for publication schema %u", psoid);
1683
1685
1686 /*
1687 * Invalidate relcache so that publication info is rebuilt. See
1688 * RemovePublicationRelById for why we need to consider all the
1689 * partitions.
1690 */
1691 schemaRels = GetSchemaPublicationRelations(pubsch->pnnspid,
1693 InvalidatePublicationRels(schemaRels);
1694
1695 CatalogTupleDelete(rel, &tup->t_self);
1696
1697 ReleaseSysCache(tup);
1698
1700}
List * GetSchemaPublicationRelations(Oid schemaid, PublicationPartOpt pub_partopt)
FormData_pg_publication_namespace * Form_pg_publication_namespace

References CatalogTupleDelete(), elog, ERROR, GetSchemaPublicationRelations(), GETSTRUCT(), HeapTupleIsValid, InvalidatePublicationRels(), NIL, ObjectIdGetDatum(), PUBLICATION_PART_ALL, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ TransformPubWhereClauses()

static void TransformPubWhereClauses ( List tables,
const char *  queryString,
bool  pubviaroot 
)
static

Definition at line 701 of file publicationcmds.c.

703{
704 ListCell *lc;
705
706 foreach(lc, tables)
707 {
708 ParseNamespaceItem *nsitem;
709 Node *whereclause = NULL;
710 ParseState *pstate;
712
713 if (pri->whereClause == NULL)
714 continue;
715
716 /*
717 * If the publication doesn't publish changes via the root partitioned
718 * table, the partition's row filter will be used. So disallow using
719 * WHERE clause on partitioned table in this case.
720 */
721 if (!pubviaroot &&
722 pri->relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
724 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
725 errmsg("cannot use publication WHERE clause for relation \"%s\"",
727 errdetail("WHERE clause cannot be used for a partitioned table when %s is false.",
728 "publish_via_partition_root")));
729
730 /*
731 * A fresh pstate is required so that we only have "this" table in its
732 * rangetable
733 */
734 pstate = make_parsestate(NULL);
735 pstate->p_sourcetext = queryString;
736 nsitem = addRangeTableEntryForRelation(pstate, pri->relation,
737 AccessShareLock, NULL,
738 false, false);
739 addNSItemToQuery(pstate, nsitem, false, true, true);
740
741 whereclause = transformWhereClause(pstate,
744 "PUBLICATION WHERE");
745
746 /* Fix up collation information */
747 assign_expr_collations(pstate, whereclause);
748
749 whereclause = expand_generated_columns_in_expr(whereclause, pri->relation, 1);
750
751 /*
752 * We allow only simple expressions in row filters. See
753 * check_simple_rowfilter_expr_walker.
754 */
755 check_simple_rowfilter_expr(whereclause, pstate);
756
757 free_parsestate(pstate);
758
759 pri->whereClause = whereclause;
760 }
761}
#define copyObject(obj)
Definition: nodes.h:232
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
void assign_expr_collations(ParseState *pstate, Node *expr)
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:72
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:39
@ EXPR_KIND_WHERE
Definition: parse_node.h:46
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
static bool check_simple_rowfilter_expr(Node *node, ParseState *pstate)
Node * expand_generated_columns_in_expr(Node *node, Relation rel, int rt_index)

References AccessShareLock, addNSItemToQuery(), addRangeTableEntryForRelation(), assign_expr_collations(), check_simple_rowfilter_expr(), copyObject, ereport, errcode(), errdetail(), errmsg(), ERROR, expand_generated_columns_in_expr(), EXPR_KIND_WHERE, free_parsestate(), lfirst, make_parsestate(), ParseState::p_sourcetext, RelationData::rd_rel, PublicationRelInfo::relation, RelationGetRelationName, transformWhereClause(), and PublicationRelInfo::whereClause.

Referenced by AlterPublicationTables(), and CreatePublication().