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 void parse_publication_options (ParseState *pstate, List *options, bool *publish_given, PublicationActions *pubactions, bool *publish_via_partition_root_given, bool *publish_via_partition_root)
 
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_collist_contains_invalid_column (Oid pubid, Relation relation, List *ancestors, bool pubviaroot)
 
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 subid, Oid newOwnerId)
 

Typedef Documentation

◆ rf_context

typedef struct rf_context rf_context

Function Documentation

◆ AlterPublication()

void AlterPublication ( ParseState pstate,
AlterPublicationStmt stmt 
)

Definition at line 1363 of file publicationcmds.c.

1364 {
1365  Relation rel;
1366  HeapTuple tup;
1367  Form_pg_publication pubform;
1368 
1369  rel = table_open(PublicationRelationId, RowExclusiveLock);
1370 
1371  tup = SearchSysCacheCopy1(PUBLICATIONNAME,
1372  CStringGetDatum(stmt->pubname));
1373 
1374  if (!HeapTupleIsValid(tup))
1375  ereport(ERROR,
1376  (errcode(ERRCODE_UNDEFINED_OBJECT),
1377  errmsg("publication \"%s\" does not exist",
1378  stmt->pubname)));
1379 
1380  pubform = (Form_pg_publication) GETSTRUCT(tup);
1381 
1382  /* must be owner */
1383  if (!object_ownercheck(PublicationRelationId, pubform->oid, GetUserId()))
1385  stmt->pubname);
1386 
1387  if (stmt->options)
1388  AlterPublicationOptions(pstate, stmt, rel, tup);
1389  else
1390  {
1391  List *relations = NIL;
1392  List *schemaidlist = NIL;
1393  Oid pubid = pubform->oid;
1394 
1395  ObjectsInPublicationToOids(stmt->pubobjects, pstate, &relations,
1396  &schemaidlist);
1397 
1398  CheckAlterPublication(stmt, tup, relations, schemaidlist);
1399 
1400  heap_freetuple(tup);
1401 
1402  /* Lock the publication so nobody else can do anything with it. */
1403  LockDatabaseObject(PublicationRelationId, pubid, 0,
1405 
1406  /*
1407  * It is possible that by the time we acquire the lock on publication,
1408  * concurrent DDL has removed it. We can test this by checking the
1409  * existence of publication. We get the tuple again to avoid the risk
1410  * of any publication option getting changed.
1411  */
1412  tup = SearchSysCacheCopy1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
1413  if (!HeapTupleIsValid(tup))
1414  ereport(ERROR,
1415  errcode(ERRCODE_UNDEFINED_OBJECT),
1416  errmsg("publication \"%s\" does not exist",
1417  stmt->pubname));
1418 
1419  AlterPublicationTables(stmt, tup, relations, pstate->p_sourcetext,
1420  schemaidlist != NIL);
1421  AlterPublicationSchemas(stmt, tup, schemaidlist);
1422  }
1423 
1424  /* Cleanup. */
1425  heap_freetuple(tup);
1427 }
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2703
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4145
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define stmt
Definition: indent_codes.h:59
void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:994
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid GetUserId(void)
Definition: miscinit.c:514
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2287
#define NIL
Definition: pg_list.h:68
FormData_pg_publication * Form_pg_publication
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
unsigned int Oid
Definition: postgres_ext.h:31
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 871 of file publicationcmds.c.

873 {
874  bool nulls[Natts_pg_publication];
875  bool replaces[Natts_pg_publication];
876  Datum values[Natts_pg_publication];
877  bool publish_given;
878  PublicationActions pubactions;
879  bool publish_via_partition_root_given;
880  bool publish_via_partition_root;
881  ObjectAddress obj;
882  Form_pg_publication pubform;
883  List *root_relids = NIL;
884  ListCell *lc;
885 
887  stmt->options,
888  &publish_given, &pubactions,
889  &publish_via_partition_root_given,
890  &publish_via_partition_root);
891 
892  pubform = (Form_pg_publication) GETSTRUCT(tup);
893 
894  /*
895  * If the publication doesn't publish changes via the root partitioned
896  * table, the partition's row filter and column list will be used. So
897  * disallow using WHERE clause and column lists on partitioned table in
898  * this case.
899  */
900  if (!pubform->puballtables && publish_via_partition_root_given &&
901  !publish_via_partition_root)
902  {
903  /*
904  * Lock the publication so nobody else can do anything with it. This
905  * prevents concurrent alter to add partitioned table(s) with WHERE
906  * clause(s) and/or column lists which we don't allow when not
907  * publishing via root.
908  */
909  LockDatabaseObject(PublicationRelationId, pubform->oid, 0,
911 
912  root_relids = GetPublicationRelations(pubform->oid,
914 
915  foreach(lc, root_relids)
916  {
917  Oid relid = lfirst_oid(lc);
918  HeapTuple rftuple;
919  char relkind;
920  char *relname;
921  bool has_rowfilter;
922  bool has_collist;
923 
924  /*
925  * Beware: we don't have lock on the relations, so cope silently
926  * with the cache lookups returning NULL.
927  */
928 
929  rftuple = SearchSysCache2(PUBLICATIONRELMAP,
930  ObjectIdGetDatum(relid),
931  ObjectIdGetDatum(pubform->oid));
932  if (!HeapTupleIsValid(rftuple))
933  continue;
934  has_rowfilter = !heap_attisnull(rftuple, Anum_pg_publication_rel_prqual, NULL);
935  has_collist = !heap_attisnull(rftuple, Anum_pg_publication_rel_prattrs, NULL);
936  if (!has_rowfilter && !has_collist)
937  {
938  ReleaseSysCache(rftuple);
939  continue;
940  }
941 
942  relkind = get_rel_relkind(relid);
943  if (relkind != RELKIND_PARTITIONED_TABLE)
944  {
945  ReleaseSysCache(rftuple);
946  continue;
947  }
948  relname = get_rel_name(relid);
949  if (relname == NULL) /* table concurrently dropped */
950  {
951  ReleaseSysCache(rftuple);
952  continue;
953  }
954 
955  if (has_rowfilter)
956  ereport(ERROR,
957  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
958  errmsg("cannot set parameter \"%s\" to false for publication \"%s\"",
959  "publish_via_partition_root",
960  stmt->pubname),
961  errdetail("The publication contains a WHERE clause for partitioned table \"%s\", which is not allowed when \"%s\" is false.",
962  relname, "publish_via_partition_root")));
963  Assert(has_collist);
964  ereport(ERROR,
965  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
966  errmsg("cannot set parameter \"%s\" to false for publication \"%s\"",
967  "publish_via_partition_root",
968  stmt->pubname),
969  errdetail("The publication contains a column list for partitioned table \"%s\", which is not allowed when \"%s\" is false.",
970  relname, "publish_via_partition_root")));
971  }
972  }
973 
974  /* Everything ok, form a new tuple. */
975  memset(values, 0, sizeof(values));
976  memset(nulls, false, sizeof(nulls));
977  memset(replaces, false, sizeof(replaces));
978 
979  if (publish_given)
980  {
981  values[Anum_pg_publication_pubinsert - 1] = BoolGetDatum(pubactions.pubinsert);
982  replaces[Anum_pg_publication_pubinsert - 1] = true;
983 
984  values[Anum_pg_publication_pubupdate - 1] = BoolGetDatum(pubactions.pubupdate);
985  replaces[Anum_pg_publication_pubupdate - 1] = true;
986 
987  values[Anum_pg_publication_pubdelete - 1] = BoolGetDatum(pubactions.pubdelete);
988  replaces[Anum_pg_publication_pubdelete - 1] = true;
989 
990  values[Anum_pg_publication_pubtruncate - 1] = BoolGetDatum(pubactions.pubtruncate);
991  replaces[Anum_pg_publication_pubtruncate - 1] = true;
992  }
993 
994  if (publish_via_partition_root_given)
995  {
996  values[Anum_pg_publication_pubviaroot - 1] = BoolGetDatum(publish_via_partition_root);
997  replaces[Anum_pg_publication_pubviaroot - 1] = true;
998  }
999 
1000  tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls,
1001  replaces);
1002 
1003  /* Update the catalog. */
1004  CatalogTupleUpdate(rel, &tup->t_self, tup);
1005 
1007 
1008  pubform = (Form_pg_publication) GETSTRUCT(tup);
1009 
1010  /* Invalidate the relcache. */
1011  if (pubform->puballtables)
1012  {
1014  }
1015  else
1016  {
1017  List *relids = NIL;
1018  List *schemarelids = NIL;
1019 
1020  /*
1021  * For any partitioned tables contained in the publication, we must
1022  * invalidate all partitions contained in the respective partition
1023  * trees, not just those explicitly mentioned in the publication.
1024  */
1025  if (root_relids == NIL)
1026  relids = GetPublicationRelations(pubform->oid,
1028  else
1029  {
1030  /*
1031  * We already got tables explicitly mentioned in the publication.
1032  * Now get all partitions for the partitioned table in the list.
1033  */
1034  foreach(lc, root_relids)
1035  relids = GetPubPartitionOptionRelations(relids,
1037  lfirst_oid(lc));
1038  }
1039 
1040  schemarelids = GetAllSchemaPublicationRelations(pubform->oid,
1042  relids = list_concat_unique_oid(relids, schemarelids);
1043 
1044  InvalidatePublicationRels(relids);
1045  }
1046 
1047  ObjectAddressSet(obj, PublicationRelationId, pubform->oid);
1049  (Node *) stmt);
1050 
1051  InvokeObjectPostAlterHook(PublicationRelationId, pubform->oid, 0);
1052 }
static Datum values[MAXATTR]
Definition: bootstrap.c:150
#define Assert(condition)
Definition: c.h:861
int errdetail(const char *fmt,...)
Definition: elog.c:1203
void EventTriggerCollectSimpleCommand(ObjectAddress address, ObjectAddress secondaryObject, Node *parsetree)
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:455
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CacheInvalidateRelcacheAll(void)
Definition: inval.c:1384
List * list_concat_unique_oid(List *list1, const List *list2)
Definition: list.c:1469
#define AccessShareLock
Definition: lockdefs.h:36
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2003
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928
#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 * GetPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
List * GetPubPartitionOptionRelations(List *result, PublicationPartOpt pub_partopt, Oid relid)
List * GetAllSchemaPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
@ PUBLICATION_PART_ROOT
@ PUBLICATION_PART_ALL
uintptr_t Datum
Definition: postgres.h:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
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)
#define RelationGetDescr(relation)
Definition: rel.h:531
ItemPointerData t_self
Definition: htup.h:65
Definition: nodes.h:129
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:232
void CommandCounterIncrement(void)
Definition: xact.c:1099

References AccessShareLock, Assert, BoolGetDatum(), CacheInvalidateRelcacheAll(), CatalogTupleUpdate(), 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, 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 1938 of file publicationcmds.c.

1939 {
1940  Oid subid;
1941  HeapTuple tup;
1942  Relation rel;
1943  ObjectAddress address;
1944  Form_pg_publication pubform;
1945 
1946  rel = table_open(PublicationRelationId, RowExclusiveLock);
1947 
1948  tup = SearchSysCacheCopy1(PUBLICATIONNAME, CStringGetDatum(name));
1949 
1950  if (!HeapTupleIsValid(tup))
1951  ereport(ERROR,
1952  (errcode(ERRCODE_UNDEFINED_OBJECT),
1953  errmsg("publication \"%s\" does not exist", name)));
1954 
1955  pubform = (Form_pg_publication) GETSTRUCT(tup);
1956  subid = pubform->oid;
1957 
1958  AlterPublicationOwner_internal(rel, tup, newOwnerId);
1959 
1960  ObjectAddressSet(address, PublicationRelationId, subid);
1961 
1962  heap_freetuple(tup);
1963 
1965 
1966  return address;
1967 }
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 1880 of file publicationcmds.c.

1881 {
1882  Form_pg_publication form;
1883 
1884  form = (Form_pg_publication) GETSTRUCT(tup);
1885 
1886  if (form->pubowner == newOwnerId)
1887  return;
1888 
1889  if (!superuser())
1890  {
1891  AclResult aclresult;
1892 
1893  /* Must be owner */
1894  if (!object_ownercheck(PublicationRelationId, form->oid, GetUserId()))
1896  NameStr(form->pubname));
1897 
1898  /* Must be able to become new owner */
1899  check_can_set_role(GetUserId(), newOwnerId);
1900 
1901  /* New owner must have CREATE privilege on database */
1902  aclresult = object_aclcheck(DatabaseRelationId, MyDatabaseId, newOwnerId, ACL_CREATE);
1903  if (aclresult != ACLCHECK_OK)
1904  aclcheck_error(aclresult, OBJECT_DATABASE,
1906 
1907  if (form->puballtables && !superuser_arg(newOwnerId))
1908  ereport(ERROR,
1909  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1910  errmsg("permission denied to change owner of publication \"%s\"",
1911  NameStr(form->pubname)),
1912  errhint("The owner of a FOR ALL TABLES publication must be a superuser.")));
1913 
1914  if (!superuser_arg(newOwnerId) && is_schema_publication(form->oid))
1915  ereport(ERROR,
1916  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1917  errmsg("permission denied to change owner of publication \"%s\"",
1918  NameStr(form->pubname)),
1919  errhint("The owner of a FOR TABLES IN SCHEMA publication must be a superuser.")));
1920  }
1921 
1922  form->pubowner = newOwnerId;
1923  CatalogTupleUpdate(rel, &tup->t_self, tup);
1924 
1925  /* Update owner dependency reference */
1926  changeDependencyOnOwner(PublicationRelationId,
1927  form->oid,
1928  newOwnerId);
1929 
1930  InvokeObjectPostAlterHook(PublicationRelationId,
1931  form->oid, 0);
1932 }
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5325
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:3891
#define NameStr(name)
Definition: c.h:749
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3187
int errhint(const char *fmt,...)
Definition: elog.c:1317
Oid MyDatabaseId
Definition: globals.c:93
@ OBJECT_DATABASE
Definition: parsenodes.h:2266
#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  subid,
Oid  newOwnerId 
)

Definition at line 1973 of file publicationcmds.c.

1974 {
1975  HeapTuple tup;
1976  Relation rel;
1977 
1978  rel = table_open(PublicationRelationId, RowExclusiveLock);
1979 
1980  tup = SearchSysCacheCopy1(PUBLICATIONOID, ObjectIdGetDatum(subid));
1981 
1982  if (!HeapTupleIsValid(tup))
1983  ereport(ERROR,
1984  (errcode(ERRCODE_UNDEFINED_OBJECT),
1985  errmsg("publication with OID %u does not exist", subid)));
1986 
1987  AlterPublicationOwner_internal(rel, tup, newOwnerId);
1988 
1989  heap_freetuple(tup);
1990 
1992 }

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 1241 of file publicationcmds.c.

1243 {
1245 
1246  /*
1247  * Nothing to do if no objects, except in SET: for that it is quite
1248  * possible that user has not specified any schemas in which case we need
1249  * to remove all the existing schemas.
1250  */
1251  if (!schemaidlist && stmt->action != AP_SetObjects)
1252  return;
1253 
1254  /*
1255  * Schema lock is held until the publication is altered to prevent
1256  * concurrent schema deletion.
1257  */
1258  LockSchemaList(schemaidlist);
1259  if (stmt->action == AP_AddObjects)
1260  {
1261  ListCell *lc;
1262  List *reloids;
1263 
1264  reloids = GetPublicationRelations(pubform->oid, PUBLICATION_PART_ROOT);
1265 
1266  foreach(lc, reloids)
1267  {
1268  HeapTuple coltuple;
1269 
1270  coltuple = SearchSysCache2(PUBLICATIONRELMAP,
1272  ObjectIdGetDatum(pubform->oid));
1273 
1274  if (!HeapTupleIsValid(coltuple))
1275  continue;
1276 
1277  /*
1278  * Disallow adding schema if column list is already part of the
1279  * publication. See CheckPubRelationColumnList.
1280  */
1281  if (!heap_attisnull(coltuple, Anum_pg_publication_rel_prattrs, NULL))
1282  ereport(ERROR,
1283  errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1284  errmsg("cannot add schema to publication \"%s\"",
1285  stmt->pubname),
1286  errdetail("Schemas cannot be added if any tables that specify a column list are already part of the publication."));
1287 
1288  ReleaseSysCache(coltuple);
1289  }
1290 
1291  PublicationAddSchemas(pubform->oid, schemaidlist, false, stmt);
1292  }
1293  else if (stmt->action == AP_DropObjects)
1294  PublicationDropSchemas(pubform->oid, schemaidlist, false);
1295  else /* AP_SetObjects */
1296  {
1297  List *oldschemaids = GetPublicationSchemas(pubform->oid);
1298  List *delschemas = NIL;
1299 
1300  /* Identify which schemas should be dropped */
1301  delschemas = list_difference_oid(oldschemaids, schemaidlist);
1302 
1303  /*
1304  * Schema lock is held until the publication is altered to prevent
1305  * concurrent schema deletion.
1306  */
1307  LockSchemaList(delschemas);
1308 
1309  /* And drop them */
1310  PublicationDropSchemas(pubform->oid, delschemas, true);
1311 
1312  /*
1313  * Don't bother calculating the difference for adding, we'll catch and
1314  * skip existing ones when doing catalog update.
1315  */
1316  PublicationAddSchemas(pubform->oid, schemaidlist, true, stmt);
1317  }
1318 }
List * list_difference_oid(const List *list1, const List *list2)
Definition: list.c:1313
@ AP_DropObjects
Definition: parsenodes.h:4190
@ AP_SetObjects
Definition: parsenodes.h:4191
@ AP_AddObjects
Definition: parsenodes.h:4189
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 1079 of file publicationcmds.c.

1082 {
1083  List *rels = NIL;
1085  Oid pubid = pubform->oid;
1086 
1087  /*
1088  * Nothing to do if no objects, except in SET: for that it is quite
1089  * possible that user has not specified any tables in which case we need
1090  * to remove all the existing tables.
1091  */
1092  if (!tables && stmt->action != AP_SetObjects)
1093  return;
1094 
1095  rels = OpenTableList(tables);
1096 
1097  if (stmt->action == AP_AddObjects)
1098  {
1099  TransformPubWhereClauses(rels, queryString, pubform->pubviaroot);
1100 
1101  publish_schema |= is_schema_publication(pubid);
1102 
1103  CheckPubRelationColumnList(stmt->pubname, rels, publish_schema,
1104  pubform->pubviaroot);
1105 
1106  PublicationAddTables(pubid, rels, false, stmt);
1107  }
1108  else if (stmt->action == AP_DropObjects)
1109  PublicationDropTables(pubid, rels, false);
1110  else /* AP_SetObjects */
1111  {
1112  List *oldrelids = GetPublicationRelations(pubid,
1114  List *delrels = NIL;
1115  ListCell *oldlc;
1116 
1117  TransformPubWhereClauses(rels, queryString, pubform->pubviaroot);
1118 
1119  CheckPubRelationColumnList(stmt->pubname, rels, publish_schema,
1120  pubform->pubviaroot);
1121 
1122  /*
1123  * To recreate the relation list for the publication, look for
1124  * existing relations that do not need to be dropped.
1125  */
1126  foreach(oldlc, oldrelids)
1127  {
1128  Oid oldrelid = lfirst_oid(oldlc);
1129  ListCell *newlc;
1130  PublicationRelInfo *oldrel;
1131  bool found = false;
1132  HeapTuple rftuple;
1133  Node *oldrelwhereclause = NULL;
1134  Bitmapset *oldcolumns = NULL;
1135 
1136  /* look up the cache for the old relmap */
1137  rftuple = SearchSysCache2(PUBLICATIONRELMAP,
1138  ObjectIdGetDatum(oldrelid),
1139  ObjectIdGetDatum(pubid));
1140 
1141  /*
1142  * See if the existing relation currently has a WHERE clause or a
1143  * column list. We need to compare those too.
1144  */
1145  if (HeapTupleIsValid(rftuple))
1146  {
1147  bool isnull = true;
1148  Datum whereClauseDatum;
1149  Datum columnListDatum;
1150 
1151  /* Load the WHERE clause for this table. */
1152  whereClauseDatum = SysCacheGetAttr(PUBLICATIONRELMAP, rftuple,
1153  Anum_pg_publication_rel_prqual,
1154  &isnull);
1155  if (!isnull)
1156  oldrelwhereclause = stringToNode(TextDatumGetCString(whereClauseDatum));
1157 
1158  /* Transform the int2vector column list to a bitmap. */
1159  columnListDatum = SysCacheGetAttr(PUBLICATIONRELMAP, rftuple,
1160  Anum_pg_publication_rel_prattrs,
1161  &isnull);
1162 
1163  if (!isnull)
1164  oldcolumns = pub_collist_to_bitmapset(NULL, columnListDatum, NULL);
1165 
1166  ReleaseSysCache(rftuple);
1167  }
1168 
1169  foreach(newlc, rels)
1170  {
1171  PublicationRelInfo *newpubrel;
1172  Oid newrelid;
1173  Bitmapset *newcolumns = NULL;
1174 
1175  newpubrel = (PublicationRelInfo *) lfirst(newlc);
1176  newrelid = RelationGetRelid(newpubrel->relation);
1177 
1178  /*
1179  * Validate the column list. If the column list or WHERE
1180  * clause changes, then the validation done here will be
1181  * duplicated inside PublicationAddTables(). The validation
1182  * is cheap enough that that seems harmless.
1183  */
1184  newcolumns = pub_collist_validate(newpubrel->relation,
1185  newpubrel->columns);
1186 
1187  /*
1188  * Check if any of the new set of relations matches with the
1189  * existing relations in the publication. Additionally, if the
1190  * relation has an associated WHERE clause, check the WHERE
1191  * expressions also match. Same for the column list. Drop the
1192  * rest.
1193  */
1194  if (newrelid == oldrelid)
1195  {
1196  if (equal(oldrelwhereclause, newpubrel->whereClause) &&
1197  bms_equal(oldcolumns, newcolumns))
1198  {
1199  found = true;
1200  break;
1201  }
1202  }
1203  }
1204 
1205  /*
1206  * Add the non-matched relations to a list so that they can be
1207  * dropped.
1208  */
1209  if (!found)
1210  {
1211  oldrel = palloc(sizeof(PublicationRelInfo));
1212  oldrel->whereClause = NULL;
1213  oldrel->columns = NIL;
1214  oldrel->relation = table_open(oldrelid,
1216  delrels = lappend(delrels, oldrel);
1217  }
1218  }
1219 
1220  /* And drop them. */
1221  PublicationDropTables(pubid, delrels, true);
1222 
1223  /*
1224  * Don't bother calculating the difference for adding, we'll catch and
1225  * skip existing ones when doing catalog update.
1226  */
1227  PublicationAddTables(pubid, rels, true, stmt);
1228 
1229  CloseTableList(delrels);
1230  }
1231 
1232  CloseTableList(rels);
1233 }
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:1317
#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:505
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:596

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 590 of file publicationcmds.c.

591 {
592  return check_simple_rowfilter_expr_walker(node, pstate);
593 }
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 483 of file publicationcmds.c.

484 {
485  char *errdetail_msg = NULL;
486 
487  if (node == NULL)
488  return false;
489 
490  switch (nodeTag(node))
491  {
492  case T_Var:
493  /* System columns are not allowed. */
494  if (((Var *) node)->varattno < InvalidAttrNumber)
495  errdetail_msg = _("System columns are not allowed.");
496  break;
497  case T_OpExpr:
498  case T_DistinctExpr:
499  case T_NullIfExpr:
500  /* OK, except user-defined operators are not allowed. */
501  if (((OpExpr *) node)->opno >= FirstNormalObjectId)
502  errdetail_msg = _("User-defined operators are not allowed.");
503  break;
504  case T_ScalarArrayOpExpr:
505  /* OK, except user-defined operators are not allowed. */
506  if (((ScalarArrayOpExpr *) node)->opno >= FirstNormalObjectId)
507  errdetail_msg = _("User-defined operators are not allowed.");
508 
509  /*
510  * We don't need to check the hashfuncid and negfuncid of
511  * ScalarArrayOpExpr as those functions are only built for a
512  * subquery.
513  */
514  break;
515  case T_RowCompareExpr:
516  {
517  ListCell *opid;
518 
519  /* OK, except user-defined operators are not allowed. */
520  foreach(opid, ((RowCompareExpr *) node)->opnos)
521  {
522  if (lfirst_oid(opid) >= FirstNormalObjectId)
523  {
524  errdetail_msg = _("User-defined operators are not allowed.");
525  break;
526  }
527  }
528  }
529  break;
530  case T_Const:
531  case T_FuncExpr:
532  case T_BoolExpr:
533  case T_RelabelType:
534  case T_CollateExpr:
535  case T_CaseExpr:
536  case T_CaseTestExpr:
537  case T_ArrayExpr:
538  case T_RowExpr:
539  case T_CoalesceExpr:
540  case T_MinMaxExpr:
541  case T_XmlExpr:
542  case T_NullTest:
543  case T_BooleanTest:
544  case T_List:
545  /* OK, supported */
546  break;
547  default:
548  errdetail_msg = _("Only columns, constants, built-in operators, built-in data types, built-in collations, and immutable built-in functions are allowed.");
549  break;
550  }
551 
552  /*
553  * For all the supported nodes, if we haven't already found a problem,
554  * check the types, functions, and collations used in it. We check List
555  * by walking through each element.
556  */
557  if (!errdetail_msg && !IsA(node, List))
558  {
559  if (exprType(node) >= FirstNormalObjectId)
560  errdetail_msg = _("User-defined types are not allowed.");
562  (void *) pstate))
563  errdetail_msg = _("User-defined or built-in mutable functions are not allowed.");
564  else if (exprCollation(node) >= FirstNormalObjectId ||
566  errdetail_msg = _("User-defined collations are not allowed.");
567  }
568 
569  /*
570  * If we found a problem in this node, throw error now. Otherwise keep
571  * going.
572  */
573  if (errdetail_msg)
574  ereport(ERROR,
575  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
576  errmsg("invalid publication WHERE expression"),
577  errdetail_internal("%s", errdetail_msg),
578  parser_errposition(pstate, exprLocation(node))));
579 
581  (void *) pstate);
582 }
#define InvalidAttrNumber
Definition: attnum.h:23
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1230
#define _(x)
Definition: elog.c:90
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
Oid exprInputCollation(const Node *expr)
Definition: nodeFuncs.c:1068
bool check_functions_in_node(Node *node, check_function_callback checker, void *context)
Definition: nodeFuncs.c:1900
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:816
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1380
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define nodeTag(nodeptr)
Definition: nodes.h:133
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:248
#define FirstNormalObjectId
Definition: transam.h:197

References _, check_functions_in_node(), 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().

◆ CheckAlterPublication()

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

Definition at line 1325 of file publicationcmds.c.

1327 {
1329 
1330  if ((stmt->action == AP_AddObjects || stmt->action == AP_SetObjects) &&
1331  schemaidlist && !superuser())
1332  ereport(ERROR,
1333  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1334  errmsg("must be superuser to add or set schemas")));
1335 
1336  /*
1337  * Check that user is allowed to manipulate the publication tables in
1338  * schema
1339  */
1340  if (schemaidlist && pubform->puballtables)
1341  ereport(ERROR,
1342  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1343  errmsg("publication \"%s\" is defined as FOR ALL TABLES",
1344  NameStr(pubform->pubname)),
1345  errdetail("Schemas cannot be added to or dropped from FOR ALL TABLES publications.")));
1346 
1347  /* Check that user is allowed to manipulate the publication tables. */
1348  if (tables && pubform->puballtables)
1349  ereport(ERROR,
1350  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1351  errmsg("publication \"%s\" is defined as FOR ALL TABLES",
1352  NameStr(pubform->pubname)),
1353  errdetail("Tables cannot be added to or dropped from FOR ALL TABLES publications.")));
1354 }

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 677 of file publicationcmds.c.

679 {
680  ListCell *lc;
681 
682  foreach(lc, tables)
683  {
685 
686  if (pri->columns == NIL)
687  continue;
688 
689  /*
690  * Disallow specifying column list if any schema is in the
691  * publication.
692  *
693  * XXX We could instead just forbid the case when the publication
694  * tries to publish the table with a column list and a schema for that
695  * table. However, if we do that then we need a restriction during
696  * ALTER TABLE ... SET SCHEMA to prevent such a case which doesn't
697  * seem to be a good idea.
698  */
699  if (publish_schema)
700  ereport(ERROR,
701  errcode(ERRCODE_INVALID_PARAMETER_VALUE),
702  errmsg("cannot use column list for relation \"%s.%s\" in publication \"%s\"",
704  RelationGetRelationName(pri->relation), pubname),
705  errdetail("Column lists cannot be specified in publications containing FOR TABLES IN SCHEMA elements."));
706 
707  /*
708  * If the publication doesn't publish changes via the root partitioned
709  * table, the partition's column list will be used. So disallow using
710  * a column list on the partitioned table in this case.
711  */
712  if (!pubviaroot &&
713  pri->relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
714  ereport(ERROR,
715  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
716  errmsg("cannot use column list for relation \"%s.%s\" in publication \"%s\"",
718  RelationGetRelationName(pri->relation), pubname),
719  errdetail("Column lists cannot be specified for partitioned tables when %s is false.",
720  "publish_via_partition_root")));
721  }
722 }
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationGetNamespace(relation)
Definition: rel.h:546
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 1691 of file publicationcmds.c.

1692 {
1693  ListCell *lc;
1694 
1695  foreach(lc, rels)
1696  {
1697  PublicationRelInfo *pub_rel;
1698 
1699  pub_rel = (PublicationRelInfo *) lfirst(lc);
1700  table_close(pub_rel->relation, NoLock);
1701  }
1702 
1703  list_free_deep(rels);
1704 }
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 219 of file publicationcmds.c.

220 {
221  if (node == NULL)
222  return false;
223 
224  if (IsA(node, Var))
225  {
226  Var *var = (Var *) node;
227  AttrNumber attnum = var->varattno;
228 
229  /*
230  * If pubviaroot is true, we are validating the row filter of the
231  * parent table, but the bitmap contains the replica identity
232  * information of the child table. So, get the column number of the
233  * child table as parent and child column order could be different.
234  */
235  if (context->pubviaroot)
236  {
237  char *colname = get_attname(context->parentid, attnum, false);
238 
239  attnum = get_attnum(context->relid, colname);
240  }
241 
243  context->bms_replident))
244  return true;
245  }
246 
248  (void *) context);
249 }
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:858
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
int16 attnum
Definition: pg_attribute.h:74
static bool contain_invalid_rfcolumn_walker(Node *node, rf_context *context)
tree context
Definition: radixtree.h:1835
AttrNumber varattno
Definition: primnodes.h:260
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27

References attnum, bms_is_member(), context, expression_tree_walker, FirstLowInvalidHeapAttributeNumber, get_attname(), get_attnum(), IsA, and Var::varattno.

Referenced by 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 438 of file publicationcmds.c.

439 {
440  return (func_volatile(func_id) != PROVOLATILE_IMMUTABLE ||
441  func_id >= FirstNormalObjectId);
442 }
char func_volatile(Oid funcid)
Definition: lsyscache.c:1780

References FirstNormalObjectId, and func_volatile().

Referenced by check_simple_rowfilter_expr_walker().

◆ CreatePublication()

ObjectAddress CreatePublication ( ParseState pstate,
CreatePublicationStmt stmt 
)

Definition at line 728 of file publicationcmds.c.

729 {
730  Relation rel;
731  ObjectAddress myself;
732  Oid puboid;
733  bool nulls[Natts_pg_publication];
734  Datum values[Natts_pg_publication];
735  HeapTuple tup;
736  bool publish_given;
737  PublicationActions pubactions;
738  bool publish_via_partition_root_given;
739  bool publish_via_partition_root;
740  AclResult aclresult;
741  List *relations = NIL;
742  List *schemaidlist = NIL;
743 
744  /* must have CREATE privilege on database */
745  aclresult = object_aclcheck(DatabaseRelationId, MyDatabaseId, GetUserId(), ACL_CREATE);
746  if (aclresult != ACLCHECK_OK)
747  aclcheck_error(aclresult, OBJECT_DATABASE,
749 
750  /* FOR ALL TABLES requires superuser */
751  if (stmt->for_all_tables && !superuser())
752  ereport(ERROR,
753  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
754  errmsg("must be superuser to create FOR ALL TABLES publication")));
755 
756  rel = table_open(PublicationRelationId, RowExclusiveLock);
757 
758  /* Check if name is used */
759  puboid = GetSysCacheOid1(PUBLICATIONNAME, Anum_pg_publication_oid,
760  CStringGetDatum(stmt->pubname));
761  if (OidIsValid(puboid))
762  ereport(ERROR,
764  errmsg("publication \"%s\" already exists",
765  stmt->pubname)));
766 
767  /* Form a tuple. */
768  memset(values, 0, sizeof(values));
769  memset(nulls, false, sizeof(nulls));
770 
771  values[Anum_pg_publication_pubname - 1] =
773  values[Anum_pg_publication_pubowner - 1] = ObjectIdGetDatum(GetUserId());
774 
776  stmt->options,
777  &publish_given, &pubactions,
778  &publish_via_partition_root_given,
779  &publish_via_partition_root);
780 
781  puboid = GetNewOidWithIndex(rel, PublicationObjectIndexId,
782  Anum_pg_publication_oid);
783  values[Anum_pg_publication_oid - 1] = ObjectIdGetDatum(puboid);
784  values[Anum_pg_publication_puballtables - 1] =
785  BoolGetDatum(stmt->for_all_tables);
786  values[Anum_pg_publication_pubinsert - 1] =
787  BoolGetDatum(pubactions.pubinsert);
788  values[Anum_pg_publication_pubupdate - 1] =
789  BoolGetDatum(pubactions.pubupdate);
790  values[Anum_pg_publication_pubdelete - 1] =
791  BoolGetDatum(pubactions.pubdelete);
792  values[Anum_pg_publication_pubtruncate - 1] =
793  BoolGetDatum(pubactions.pubtruncate);
794  values[Anum_pg_publication_pubviaroot - 1] =
795  BoolGetDatum(publish_via_partition_root);
796 
797  tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
798 
799  /* Insert tuple into catalog. */
800  CatalogTupleInsert(rel, tup);
801  heap_freetuple(tup);
802 
803  recordDependencyOnOwner(PublicationRelationId, puboid, GetUserId());
804 
805  ObjectAddressSet(myself, PublicationRelationId, puboid);
806 
807  /* Make the changes visible. */
809 
810  /* Associate objects with the publication. */
811  if (stmt->for_all_tables)
812  {
813  /* Invalidate relcache so that publication info is rebuilt. */
815  }
816  else
817  {
818  ObjectsInPublicationToOids(stmt->pubobjects, pstate, &relations,
819  &schemaidlist);
820 
821  /* FOR TABLES IN SCHEMA requires superuser */
822  if (schemaidlist != NIL && !superuser())
823  ereport(ERROR,
824  errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
825  errmsg("must be superuser to create FOR TABLES IN SCHEMA publication"));
826 
827  if (relations != NIL)
828  {
829  List *rels;
830 
831  rels = OpenTableList(relations);
833  publish_via_partition_root);
834 
835  CheckPubRelationColumnList(stmt->pubname, rels,
836  schemaidlist != NIL,
837  publish_via_partition_root);
838 
839  PublicationAddTables(puboid, rels, true, NULL);
840  CloseTableList(rels);
841  }
842 
843  if (schemaidlist != NIL)
844  {
845  /*
846  * Schema lock is held until the publication is created to prevent
847  * concurrent schema deletion.
848  */
849  LockSchemaList(schemaidlist);
850  PublicationAddSchemas(puboid, schemaidlist, true, NULL);
851  }
852  }
853 
855 
856  InvokeObjectPostCreateHook(PublicationRelationId, puboid, 0);
857 
860  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
861  errmsg("\"wal_level\" is insufficient to publish logical changes"),
862  errhint("Set \"wal_level\" to \"logical\" before creating subscriptions.")));
863 
864  return myself;
865 }
#define OidIsValid(objectId)
Definition: c.h:778
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
#define WARNING
Definition: elog.h:36
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:641
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
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:32
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:109
int wal_level
Definition: xlog.c:130
@ WAL_LEVEL_LOGICAL
Definition: xlog.h:76

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, BoolGetDatum(), CacheInvalidateRelcacheAll(), CatalogTupleInsert(), 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, 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().

◆ InvalidatePublicationRels()

void InvalidatePublicationRels ( List relids)

Definition at line 1058 of file publicationcmds.c.

1059 {
1060  /*
1061  * We don't want to send too many individual messages, at some point it's
1062  * cheaper to just reset whole relcache.
1063  */
1064  if (list_length(relids) < MAX_RELCACHE_INVAL_MSGS)
1065  {
1066  ListCell *lc;
1067 
1068  foreach(lc, relids)
1070  }
1071  else
1073 }
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1419
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().

◆ LockSchemaList()

static void LockSchemaList ( List schemalist)
static

Definition at line 1711 of file publicationcmds.c.

1712 {
1713  ListCell *lc;
1714 
1715  foreach(lc, schemalist)
1716  {
1717  Oid schemaid = lfirst_oid(lc);
1718 
1719  /* Allow query cancel in case this takes a long time */
1721  LockDatabaseObject(NamespaceRelationId, schemaid, 0, AccessShareLock);
1722 
1723  /*
1724  * It is possible that by the time we acquire the lock on schema,
1725  * concurrent DDL has removed it. We can test this by checking the
1726  * existence of schema.
1727  */
1728  if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaid)))
1729  ereport(ERROR,
1730  errcode(ERRCODE_UNDEFINED_SCHEMA),
1731  errmsg("schema with OID %u does not exist", schemaid));
1732  }
1733 }
#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 166 of file publicationcmds.c.

168 {
169  ListCell *cell;
170  PublicationObjSpec *pubobj;
171 
172  if (!pubobjspec_list)
173  return;
174 
175  foreach(cell, pubobjspec_list)
176  {
177  Oid schemaid;
178  List *search_path;
179 
180  pubobj = (PublicationObjSpec *) lfirst(cell);
181 
182  switch (pubobj->pubobjtype)
183  {
185  *rels = lappend(*rels, pubobj->pubtable);
186  break;
188  schemaid = get_namespace_oid(pubobj->name, false);
189 
190  /* Filter out duplicates if user specifies "sch1, sch1" */
191  *schemas = list_append_unique_oid(*schemas, schemaid);
192  break;
194  search_path = fetch_search_path(false);
195  if (search_path == NIL) /* nothing valid in search_path? */
196  ereport(ERROR,
197  errcode(ERRCODE_UNDEFINED_SCHEMA),
198  errmsg("no schema has been selected for CURRENT_SCHEMA"));
199 
200  schemaid = linitial_oid(search_path);
201  list_free(search_path);
202 
203  /* Filter out duplicates if user specifies "sch1, sch1" */
204  *schemas = list_append_unique_oid(*schemas, schemaid);
205  break;
206  default:
207  /* shouldn't happen */
208  elog(ERROR, "invalid publication object type %d", pubobj->pubobjtype);
209  break;
210  }
211  }
212 }
#define elog(elevel,...)
Definition: elog.h:225
void list_free(List *list)
Definition: list.c:1546
List * list_append_unique_oid(List *list, Oid datum)
Definition: list.c:1380
List * fetch_search_path(bool includeImplicit)
Definition: namespace.c:4809
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3520
@ PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA
Definition: parsenodes.h:4164
@ PUBLICATIONOBJ_TABLES_IN_SCHEMA
Definition: parsenodes.h:4163
@ PUBLICATIONOBJ_TABLE
Definition: parsenodes.h:4162
#define linitial_oid(l)
Definition: pg_list.h:180
PublicationObjSpecType pubobjtype
Definition: parsenodes.h:4172
PublicationTable * pubtable
Definition: parsenodes.h:4174

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 1541 of file publicationcmds.c.

1542 {
1543  List *relids = NIL;
1544  List *rels = NIL;
1545  ListCell *lc;
1546  List *relids_with_rf = NIL;
1547  List *relids_with_collist = NIL;
1548 
1549  /*
1550  * Open, share-lock, and check all the explicitly-specified relations
1551  */
1552  foreach(lc, tables)
1553  {
1555  bool recurse = t->relation->inh;
1556  Relation rel;
1557  Oid myrelid;
1558  PublicationRelInfo *pub_rel;
1559 
1560  /* Allow query cancel in case this takes a long time */
1562 
1564  myrelid = RelationGetRelid(rel);
1565 
1566  /*
1567  * Filter out duplicates if user specifies "foo, foo".
1568  *
1569  * Note that this algorithm is known to not be very efficient (O(N^2))
1570  * but given that it only works on list of tables given to us by user
1571  * it's deemed acceptable.
1572  */
1573  if (list_member_oid(relids, myrelid))
1574  {
1575  /* Disallow duplicate tables if there are any with row filters. */
1576  if (t->whereClause || list_member_oid(relids_with_rf, myrelid))
1577  ereport(ERROR,
1579  errmsg("conflicting or redundant WHERE clauses for table \"%s\"",
1580  RelationGetRelationName(rel))));
1581 
1582  /* Disallow duplicate tables if there are any with column lists. */
1583  if (t->columns || list_member_oid(relids_with_collist, myrelid))
1584  ereport(ERROR,
1586  errmsg("conflicting or redundant column lists for table \"%s\"",
1587  RelationGetRelationName(rel))));
1588 
1590  continue;
1591  }
1592 
1593  pub_rel = palloc(sizeof(PublicationRelInfo));
1594  pub_rel->relation = rel;
1595  pub_rel->whereClause = t->whereClause;
1596  pub_rel->columns = t->columns;
1597  rels = lappend(rels, pub_rel);
1598  relids = lappend_oid(relids, myrelid);
1599 
1600  if (t->whereClause)
1601  relids_with_rf = lappend_oid(relids_with_rf, myrelid);
1602 
1603  if (t->columns)
1604  relids_with_collist = lappend_oid(relids_with_collist, myrelid);
1605 
1606  /*
1607  * Add children of this rel, if requested, so that they too are added
1608  * to the publication. A partitioned table can't have any inheritance
1609  * children other than its partitions, which need not be explicitly
1610  * added to the publication.
1611  */
1612  if (recurse && rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1613  {
1614  List *children;
1615  ListCell *child;
1616 
1617  children = find_all_inheritors(myrelid, ShareUpdateExclusiveLock,
1618  NULL);
1619 
1620  foreach(child, children)
1621  {
1622  Oid childrelid = lfirst_oid(child);
1623 
1624  /* Allow query cancel in case this takes a long time */
1626 
1627  /*
1628  * Skip duplicates if user specified both parent and child
1629  * tables.
1630  */
1631  if (list_member_oid(relids, childrelid))
1632  {
1633  /*
1634  * We don't allow to specify row filter for both parent
1635  * and child table at the same time as it is not very
1636  * clear which one should be given preference.
1637  */
1638  if (childrelid != myrelid &&
1639  (t->whereClause || list_member_oid(relids_with_rf, childrelid)))
1640  ereport(ERROR,
1642  errmsg("conflicting or redundant WHERE clauses for table \"%s\"",
1643  RelationGetRelationName(rel))));
1644 
1645  /*
1646  * We don't allow to specify column list for both parent
1647  * and child table at the same time as it is not very
1648  * clear which one should be given preference.
1649  */
1650  if (childrelid != myrelid &&
1651  (t->columns || list_member_oid(relids_with_collist, childrelid)))
1652  ereport(ERROR,
1654  errmsg("conflicting or redundant column lists for table \"%s\"",
1655  RelationGetRelationName(rel))));
1656 
1657  continue;
1658  }
1659 
1660  /* find_all_inheritors already got lock */
1661  rel = table_open(childrelid, NoLock);
1662  pub_rel = palloc(sizeof(PublicationRelInfo));
1663  pub_rel->relation = rel;
1664  /* child inherits WHERE clause from parent */
1665  pub_rel->whereClause = t->whereClause;
1666 
1667  /* child inherits column list from parent */
1668  pub_rel->columns = t->columns;
1669  rels = lappend(rels, pub_rel);
1670  relids = lappend_oid(relids, childrelid);
1671 
1672  if (t->whereClause)
1673  relids_with_rf = lappend_oid(relids_with_rf, childrelid);
1674 
1675  if (t->columns)
1676  relids_with_collist = lappend_oid(relids_with_collist, childrelid);
1677  }
1678  }
1679  }
1680 
1681  list_free(relids);
1682  list_free(relids_with_rf);
1683 
1684  return rels;
1685 }
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:4152
bool inh
Definition: primnodes.h:85
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 
)
static

Definition at line 76 of file publicationcmds.c.

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

References defGetBoolean(), 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_collist_contains_invalid_column()

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

Definition at line 334 of file publicationcmds.c.

336 {
337  HeapTuple tuple;
338  Oid relid = RelationGetRelid(relation);
339  Oid publish_as_relid = RelationGetRelid(relation);
340  bool result = false;
341  Datum datum;
342  bool isnull;
343 
344  /*
345  * For a partition, if pubviaroot is true, find the topmost ancestor that
346  * is published via this publication as we need to use its column list for
347  * the changes.
348  *
349  * Note that even though the column list used is for an ancestor, the
350  * REPLICA IDENTITY used will be for the actual child table.
351  */
352  if (pubviaroot && relation->rd_rel->relispartition)
353  {
354  publish_as_relid = GetTopMostAncestorInPublication(pubid, ancestors, NULL);
355 
356  if (!OidIsValid(publish_as_relid))
357  publish_as_relid = relid;
358  }
359 
360  tuple = SearchSysCache2(PUBLICATIONRELMAP,
361  ObjectIdGetDatum(publish_as_relid),
362  ObjectIdGetDatum(pubid));
363 
364  if (!HeapTupleIsValid(tuple))
365  return false;
366 
367  datum = SysCacheGetAttr(PUBLICATIONRELMAP, tuple,
368  Anum_pg_publication_rel_prattrs,
369  &isnull);
370 
371  if (!isnull)
372  {
373  int x;
374  Bitmapset *idattrs;
375  Bitmapset *columns = NULL;
376 
377  /* With REPLICA IDENTITY FULL, no column list is allowed. */
378  if (relation->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
379  result = true;
380 
381  /* Transform the column list datum to a bitmapset. */
382  columns = pub_collist_to_bitmapset(NULL, datum, NULL);
383 
384  /* Remember columns that are part of the REPLICA IDENTITY */
385  idattrs = RelationGetIndexAttrBitmap(relation,
387 
388  /*
389  * Attnums in the bitmap returned by RelationGetIndexAttrBitmap are
390  * offset (to handle system columns the usual way), while column list
391  * does not use offset, so we can't do bms_is_subset(). Instead, we
392  * have to loop over the idattrs and check all of them are in the
393  * list.
394  */
395  x = -1;
396  while ((x = bms_next_member(idattrs, x)) >= 0)
397  {
399 
400  /*
401  * If pubviaroot is true, we are validating the column list of the
402  * parent table, but the bitmap contains the replica identity
403  * information of the child table. The parent/child attnums may
404  * not match, so translate them to the parent - get the attname
405  * from the child, and look it up in the parent.
406  */
407  if (pubviaroot)
408  {
409  /* attribute name in the child table */
410  char *colname = get_attname(relid, attnum, false);
411 
412  /*
413  * Determine the attnum for the attribute name in parent (we
414  * are using the column list defined on the parent).
415  */
416  attnum = get_attnum(publish_as_relid, colname);
417  }
418 
419  /* replica identity column, not covered by the column list */
420  if (!bms_is_member(attnum, columns))
421  {
422  result = true;
423  break;
424  }
425  }
426 
427  bms_free(idattrs);
428  bms_free(columns);
429  }
430 
431  ReleaseSysCache(tuple);
432 
433  return result;
434 }
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:71
Oid GetTopMostAncestorInPublication(Oid puboid, List *ancestors, int *ancestor_level)
Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Definition: relcache.c:5247
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:63

References attnum, bms_free(), bms_is_member(), bms_next_member(), FirstLowInvalidHeapAttributeNumber, get_attname(), get_attnum(), GetTopMostAncestorInPublication(), HeapTupleIsValid, INDEX_ATTR_BITMAP_IDENTITY_KEY, ObjectIdGetDatum(), OidIsValid, pub_collist_to_bitmapset(), RelationData::rd_rel, RelationGetIndexAttrBitmap(), RelationGetRelid, ReleaseSysCache(), SearchSysCache2(), SysCacheGetAttr(), 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 258 of file publicationcmds.c.

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

References contain_invalid_rfcolumn_walker(), context, GetTopMostAncestorInPublication(), HeapTupleIsValid, INDEX_ATTR_BITMAP_IDENTITY_KEY, ObjectIdGetDatum(), OidIsValid, RelationData::rd_rel, RelationGetIndexAttrBitmap(), RelationGetRelid, ReleaseSysCache(), 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 1818 of file publicationcmds.c.

1820 {
1821  ListCell *lc;
1822 
1823  Assert(!stmt || !stmt->for_all_tables);
1824 
1825  foreach(lc, schemas)
1826  {
1827  Oid schemaid = lfirst_oid(lc);
1828  ObjectAddress obj;
1829 
1830  obj = publication_add_schema(pubid, schemaid, if_not_exists);
1831  if (stmt)
1832  {
1834  (Node *) stmt);
1835 
1836  InvokeObjectPostCreateHook(PublicationNamespaceRelationId,
1837  obj.objectId, 0);
1838  }
1839  }
1840 }
ObjectAddress publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists)

References Assert, 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 1739 of file publicationcmds.c.

1741 {
1742  ListCell *lc;
1743 
1744  Assert(!stmt || !stmt->for_all_tables);
1745 
1746  foreach(lc, rels)
1747  {
1748  PublicationRelInfo *pub_rel = (PublicationRelInfo *) lfirst(lc);
1749  Relation rel = pub_rel->relation;
1750  ObjectAddress obj;
1751 
1752  /* Must be owner of the table or superuser. */
1753  if (!object_ownercheck(RelationRelationId, RelationGetRelid(rel), GetUserId()))
1756 
1757  obj = publication_add_relation(pubid, pub_rel, if_not_exists);
1758  if (stmt)
1759  {
1761  (Node *) stmt);
1762 
1763  InvokeObjectPostCreateHook(PublicationRelRelationId,
1764  obj.objectId, 0);
1765  }
1766  }
1767 }
ObjectType get_relkind_objtype(char relkind)
ObjectAddress publication_add_relation(Oid pubid, PublicationRelInfo *pri, bool if_not_exists)

References aclcheck_error(), ACLCHECK_NOT_OWNER, Assert, 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 1846 of file publicationcmds.c.

1847 {
1848  ObjectAddress obj;
1849  ListCell *lc;
1850  Oid psid;
1851 
1852  foreach(lc, schemas)
1853  {
1854  Oid schemaid = lfirst_oid(lc);
1855 
1856  psid = GetSysCacheOid2(PUBLICATIONNAMESPACEMAP,
1857  Anum_pg_publication_namespace_oid,
1858  ObjectIdGetDatum(schemaid),
1859  ObjectIdGetDatum(pubid));
1860  if (!OidIsValid(psid))
1861  {
1862  if (missing_ok)
1863  continue;
1864 
1865  ereport(ERROR,
1866  (errcode(ERRCODE_UNDEFINED_OBJECT),
1867  errmsg("tables from schema \"%s\" are not part of the publication",
1868  get_namespace_name(schemaid))));
1869  }
1870 
1871  ObjectAddressSet(obj, PublicationNamespaceRelationId, psid);
1872  performDeletion(&obj, DROP_CASCADE, 0);
1873  }
1874 }
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:273
@ DROP_CASCADE
Definition: parsenodes.h:2331
#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 1773 of file publicationcmds.c.

1774 {
1775  ObjectAddress obj;
1776  ListCell *lc;
1777  Oid prid;
1778 
1779  foreach(lc, rels)
1780  {
1781  PublicationRelInfo *pubrel = (PublicationRelInfo *) lfirst(lc);
1782  Relation rel = pubrel->relation;
1783  Oid relid = RelationGetRelid(rel);
1784 
1785  if (pubrel->columns)
1786  ereport(ERROR,
1787  errcode(ERRCODE_SYNTAX_ERROR),
1788  errmsg("column list must not be specified in ALTER PUBLICATION ... DROP"));
1789 
1790  prid = GetSysCacheOid2(PUBLICATIONRELMAP, Anum_pg_publication_rel_oid,
1791  ObjectIdGetDatum(relid),
1792  ObjectIdGetDatum(pubid));
1793  if (!OidIsValid(prid))
1794  {
1795  if (missing_ok)
1796  continue;
1797 
1798  ereport(ERROR,
1799  (errcode(ERRCODE_UNDEFINED_OBJECT),
1800  errmsg("relation \"%s\" is not part of the publication",
1801  RelationGetRelationName(rel))));
1802  }
1803 
1804  if (pubrel->whereClause)
1805  ereport(ERROR,
1806  (errcode(ERRCODE_SYNTAX_ERROR),
1807  errmsg("cannot use a WHERE clause when removing a table from a publication")));
1808 
1809  ObjectAddressSet(obj, PublicationRelRelationId, prid);
1810  performDeletion(&obj, DROP_CASCADE, 0);
1811  }
1812 }

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 1474 of file publicationcmds.c.

1475 {
1476  Relation rel;
1477  HeapTuple tup;
1478  Form_pg_publication pubform;
1479 
1480  rel = table_open(PublicationRelationId, RowExclusiveLock);
1481 
1482  tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
1483  if (!HeapTupleIsValid(tup))
1484  elog(ERROR, "cache lookup failed for publication %u", pubid);
1485 
1486  pubform = (Form_pg_publication) GETSTRUCT(tup);
1487 
1488  /* Invalidate relcache so that publication info is rebuilt. */
1489  if (pubform->puballtables)
1491 
1492  CatalogTupleDelete(rel, &tup->t_self);
1493 
1494  ReleaseSysCache(tup);
1495 
1497 }
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

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 1433 of file publicationcmds.c.

1434 {
1435  Relation rel;
1436  HeapTuple tup;
1437  Form_pg_publication_rel pubrel;
1438  List *relids = NIL;
1439 
1440  rel = table_open(PublicationRelRelationId, RowExclusiveLock);
1441 
1442  tup = SearchSysCache1(PUBLICATIONREL, ObjectIdGetDatum(proid));
1443 
1444  if (!HeapTupleIsValid(tup))
1445  elog(ERROR, "cache lookup failed for publication table %u",
1446  proid);
1447 
1448  pubrel = (Form_pg_publication_rel) GETSTRUCT(tup);
1449 
1450  /*
1451  * Invalidate relcache so that publication info is rebuilt.
1452  *
1453  * For the partitioned tables, we must invalidate all partitions contained
1454  * in the respective partition hierarchies, not just the one explicitly
1455  * mentioned in the publication. This is required because we implicitly
1456  * publish the child tables when the parent table is published.
1457  */
1459  pubrel->prrelid);
1460 
1461  InvalidatePublicationRels(relids);
1462 
1463  CatalogTupleDelete(rel, &tup->t_self);
1464 
1465  ReleaseSysCache(tup);
1466 
1468 }
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 1503 of file publicationcmds.c.

1504 {
1505  Relation rel;
1506  HeapTuple tup;
1507  List *schemaRels = NIL;
1509 
1510  rel = table_open(PublicationNamespaceRelationId, RowExclusiveLock);
1511 
1512  tup = SearchSysCache1(PUBLICATIONNAMESPACE, ObjectIdGetDatum(psoid));
1513 
1514  if (!HeapTupleIsValid(tup))
1515  elog(ERROR, "cache lookup failed for publication schema %u", psoid);
1516 
1517  pubsch = (Form_pg_publication_namespace) GETSTRUCT(tup);
1518 
1519  /*
1520  * Invalidate relcache so that publication info is rebuilt. See
1521  * RemovePublicationRelById for why we need to consider all the
1522  * partitions.
1523  */
1524  schemaRels = GetSchemaPublicationRelations(pubsch->pnnspid,
1526  InvalidatePublicationRels(schemaRels);
1527 
1528  CatalogTupleDelete(rel, &tup->t_self);
1529 
1530  ReleaseSysCache(tup);
1531 
1533 }
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 605 of file publicationcmds.c.

607 {
608  ListCell *lc;
609 
610  foreach(lc, tables)
611  {
612  ParseNamespaceItem *nsitem;
613  Node *whereclause = NULL;
614  ParseState *pstate;
616 
617  if (pri->whereClause == NULL)
618  continue;
619 
620  /*
621  * If the publication doesn't publish changes via the root partitioned
622  * table, the partition's row filter will be used. So disallow using
623  * WHERE clause on partitioned table in this case.
624  */
625  if (!pubviaroot &&
626  pri->relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
627  ereport(ERROR,
628  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
629  errmsg("cannot use publication WHERE clause for relation \"%s\"",
631  errdetail("WHERE clause cannot be used for a partitioned table when %s is false.",
632  "publish_via_partition_root")));
633 
634  /*
635  * A fresh pstate is required so that we only have "this" table in its
636  * rangetable
637  */
638  pstate = make_parsestate(NULL);
639  pstate->p_sourcetext = queryString;
640  nsitem = addRangeTableEntryForRelation(pstate, pri->relation,
641  AccessShareLock, NULL,
642  false, false);
643  addNSItemToQuery(pstate, nsitem, false, true, true);
644 
645  whereclause = transformWhereClause(pstate,
646  copyObject(pri->whereClause),
648  "PUBLICATION WHERE");
649 
650  /* Fix up collation information */
651  assign_expr_collations(pstate, whereclause);
652 
653  /*
654  * We allow only simple expressions in row filters. See
655  * check_simple_rowfilter_expr_walker.
656  */
657  check_simple_rowfilter_expr(whereclause, pstate);
658 
659  free_parsestate(pstate);
660 
661  pri->whereClause = whereclause;
662  }
663 }
#define copyObject(obj)
Definition: nodes.h:224
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)

References AccessShareLock, addNSItemToQuery(), addRangeTableEntryForRelation(), assign_expr_collations(), check_simple_rowfilter_expr(), copyObject, ereport, errcode(), errdetail(), errmsg(), ERROR, 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().