PostgreSQL Source Code  git master
tablecmds.h File Reference
#include "access/htup.h"
#include "catalog/dependency.h"
#include "catalog/objectaddress.h"
#include "nodes/parsenodes.h"
#include "storage/lock.h"
#include "utils/relcache.h"
Include dependency graph for tablecmds.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

ObjectAddress DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
 
void RemoveRelations (DropStmt *drop)
 
Oid AlterTableLookupRelation (AlterTableStmt *stmt, LOCKMODE lockmode)
 
void AlterTable (AlterTableStmt *stmt, LOCKMODE lockmode, struct AlterTableUtilityContext *context)
 
LOCKMODE AlterTableGetLockLevel (List *cmds)
 
void ATExecChangeOwner (Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
 
void AlterTableInternal (Oid relid, List *cmds, bool recurse)
 
Oid AlterTableMoveAll (AlterTableMoveAllStmt *stmt)
 
ObjectAddress AlterTableNamespace (AlterObjectSchemaStmt *stmt, Oid *oldschema)
 
void AlterTableNamespaceInternal (Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
 
void AlterRelationNamespaceInternal (Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
 
void CheckTableNotInUse (Relation rel, const char *stmt)
 
void ExecuteTruncate (TruncateStmt *stmt)
 
void ExecuteTruncateGuts (List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs)
 
void SetRelationHasSubclass (Oid relationId, bool relhassubclass)
 
bool CheckRelationTableSpaceMove (Relation rel, Oid newTableSpaceId)
 
void SetRelationTableSpace (Relation rel, Oid newTableSpaceId, Oid newRelFileNode)
 
ObjectAddress renameatt (RenameStmt *stmt)
 
ObjectAddress RenameConstraint (RenameStmt *stmt)
 
ObjectAddress RenameRelation (RenameStmt *stmt)
 
void RenameRelationInternal (Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
 
void ResetRelRewrite (Oid myrelid)
 
void find_composite_type_dependencies (Oid typeOid, Relation origRelation, const char *origTypeName)
 
void check_of_type (HeapTuple typetuple)
 
void register_on_commit_action (Oid relid, OnCommitAction action)
 
void remove_on_commit_action (Oid relid)
 
void PreCommit_on_commit_actions (void)
 
void AtEOXact_on_commit_actions (bool isCommit)
 
void AtEOSubXact_on_commit_actions (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
void RangeVarCallbackOwnsTable (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
void RangeVarCallbackOwnsRelation (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
bool PartConstraintImpliedByRelConstraint (Relation scanrel, List *partConstraint)
 

Function Documentation

◆ AlterRelationNamespaceInternal()

void AlterRelationNamespaceInternal ( Relation  classRel,
Oid  relOid,
Oid  oldNspOid,
Oid  newNspOid,
bool  hasDependEntry,
ObjectAddresses objsMoved 
)

Definition at line 16026 of file tablecmds.c.

References add_exact_object_address(), Assert, CatalogTupleUpdate(), changeDependencyFor(), ObjectAddress::classId, elog, ereport, errcode(), errmsg(), ERROR, get_namespace_name(), get_relname_relid(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHook, NameStr, object_address_present(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, RELOID, SearchSysCacheCopy1, and HeapTupleData::t_self.

Referenced by AlterIndexNamespaces(), AlterSeqNamespaces(), AlterTableNamespaceInternal(), and AlterTypeNamespaceInternal().

16030 {
16031  HeapTuple classTup;
16032  Form_pg_class classForm;
16033  ObjectAddress thisobj;
16034  bool already_done = false;
16035 
16036  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
16037  if (!HeapTupleIsValid(classTup))
16038  elog(ERROR, "cache lookup failed for relation %u", relOid);
16039  classForm = (Form_pg_class) GETSTRUCT(classTup);
16040 
16041  Assert(classForm->relnamespace == oldNspOid);
16042 
16043  thisobj.classId = RelationRelationId;
16044  thisobj.objectId = relOid;
16045  thisobj.objectSubId = 0;
16046 
16047  /*
16048  * If the object has already been moved, don't move it again. If it's
16049  * already in the right place, don't move it, but still fire the object
16050  * access hook.
16051  */
16052  already_done = object_address_present(&thisobj, objsMoved);
16053  if (!already_done && oldNspOid != newNspOid)
16054  {
16055  /* check for duplicate name (more friendly than unique-index failure) */
16056  if (get_relname_relid(NameStr(classForm->relname),
16057  newNspOid) != InvalidOid)
16058  ereport(ERROR,
16059  (errcode(ERRCODE_DUPLICATE_TABLE),
16060  errmsg("relation \"%s\" already exists in schema \"%s\"",
16061  NameStr(classForm->relname),
16062  get_namespace_name(newNspOid))));
16063 
16064  /* classTup is a copy, so OK to scribble on */
16065  classForm->relnamespace = newNspOid;
16066 
16067  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
16068 
16069  /* Update dependency on schema if caller said so */
16070  if (hasDependEntry &&
16071  changeDependencyFor(RelationRelationId,
16072  relOid,
16073  NamespaceRelationId,
16074  oldNspOid,
16075  newNspOid) != 1)
16076  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
16077  NameStr(classForm->relname));
16078  }
16079  if (!already_done)
16080  {
16081  add_exact_object_address(&thisobj, objsMoved);
16082 
16083  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
16084  }
16085 
16086  heap_freetuple(classTup);
16087 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2545
int errcode(int sqlerrcode)
Definition: elog.c:698
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2485
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1856
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
int errmsg(const char *fmt,...)
Definition: elog.c:909
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:399
#define elog(elevel,...)
Definition: elog.h:232
#define NameStr(name)
Definition: c.h:681

◆ AlterTable()

void AlterTable ( AlterTableStmt stmt,
LOCKMODE  lockmode,
struct AlterTableUtilityContext context 
)

Definition at line 3993 of file tablecmds.c.

References ATController(), CheckTableNotInUse(), AlterTableStmt::cmds, RangeVar::inh, NoLock, AlterTableStmt::relation, relation_open(), and AlterTableUtilityContext::relid.

Referenced by ProcessUtilitySlow().

3995 {
3996  Relation rel;
3997 
3998  /* Caller is required to provide an adequate lock. */
3999  rel = relation_open(context->relid, NoLock);
4000 
4001  CheckTableNotInUse(rel, "ALTER TABLE");
4002 
4003  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4004 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4338
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3909
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1871

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4067 of file tablecmds.c.

References AccessExclusiveLock, AccessShareLock, AlterTableGetRelOptionsLockLevel(), AT_AddColumn, AT_AddColumnToView, AT_AddConstraint, AT_AddConstraintRecurse, AT_AddIdentity, AT_AddIndex, AT_AddIndexConstraint, AT_AddInherit, AT_AddOf, AT_AlterColumnGenericOptions, AT_AlterColumnType, AT_AlterConstraint, AT_AttachPartition, AT_ChangeOwner, AT_CheckNotNull, AT_ClusterOn, AT_ColumnDefault, AT_CookedColumnDefault, AT_DetachPartition, AT_DetachPartitionFinalize, AT_DisableRowSecurity, AT_DisableRule, AT_DisableTrig, AT_DisableTrigAll, AT_DisableTrigUser, AT_DropCluster, AT_DropColumn, AT_DropConstraint, AT_DropExpression, AT_DropIdentity, AT_DropInherit, AT_DropNotNull, AT_DropOf, AT_DropOids, AT_EnableAlwaysRule, AT_EnableAlwaysTrig, AT_EnableReplicaRule, AT_EnableReplicaTrig, AT_EnableRowSecurity, AT_EnableRule, AT_EnableTrig, AT_EnableTrigAll, AT_EnableTrigUser, AT_ForceRowSecurity, AT_GenericOptions, AT_NoForceRowSecurity, AT_ReAddConstraint, AT_ReAddDomainConstraint, AT_ReplaceRelOptions, AT_ReplicaIdentity, AT_ResetOptions, AT_ResetRelOptions, AT_SetAccessMethod, AT_SetCompression, AT_SetIdentity, AT_SetLogged, AT_SetNotNull, AT_SetOptions, AT_SetRelOptions, AT_SetStatistics, AT_SetStorage, AT_SetTableSpace, AT_SetUnLogged, AT_ValidateConstraint, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_PRIMARY, CONSTR_UNIQUE, Constraint::contype, AlterTableCmd::def, elog, ERROR, IsA, lfirst, ShareRowExclusiveLock, ShareUpdateExclusiveLock, and AlterTableCmd::subtype.

Referenced by AlterTableInternal(), and ProcessUtilitySlow().

4068 {
4069  /*
4070  * This only works if we read catalog tables using MVCC snapshots.
4071  */
4072  ListCell *lcmd;
4074 
4075  foreach(lcmd, cmds)
4076  {
4077  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4078  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4079 
4080  switch (cmd->subtype)
4081  {
4082  /*
4083  * These subcommands rewrite the heap, so require full locks.
4084  */
4085  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4086  * to SELECT */
4087  case AT_SetAccessMethod: /* must rewrite heap */
4088  case AT_SetTableSpace: /* must rewrite heap */
4089  case AT_AlterColumnType: /* must rewrite heap */
4090  cmd_lockmode = AccessExclusiveLock;
4091  break;
4092 
4093  /*
4094  * These subcommands may require addition of toast tables. If
4095  * we add a toast table to a table currently being scanned, we
4096  * might miss data added to the new toast table by concurrent
4097  * insert transactions.
4098  */
4099  case AT_SetStorage: /* may add toast tables, see
4100  * ATRewriteCatalogs() */
4101  cmd_lockmode = AccessExclusiveLock;
4102  break;
4103 
4104  /*
4105  * Removing constraints can affect SELECTs that have been
4106  * optimized assuming the constraint holds true. See also
4107  * CloneFkReferenced.
4108  */
4109  case AT_DropConstraint: /* as DROP INDEX */
4110  case AT_DropNotNull: /* may change some SQL plans */
4111  cmd_lockmode = AccessExclusiveLock;
4112  break;
4113 
4114  /*
4115  * Subcommands that may be visible to concurrent SELECTs
4116  */
4117  case AT_DropColumn: /* change visible to SELECT */
4118  case AT_AddColumnToView: /* CREATE VIEW */
4119  case AT_DropOids: /* used to equiv to DropColumn */
4120  case AT_EnableAlwaysRule: /* may change SELECT rules */
4121  case AT_EnableReplicaRule: /* may change SELECT rules */
4122  case AT_EnableRule: /* may change SELECT rules */
4123  case AT_DisableRule: /* may change SELECT rules */
4124  cmd_lockmode = AccessExclusiveLock;
4125  break;
4126 
4127  /*
4128  * Changing owner may remove implicit SELECT privileges
4129  */
4130  case AT_ChangeOwner: /* change visible to SELECT */
4131  cmd_lockmode = AccessExclusiveLock;
4132  break;
4133 
4134  /*
4135  * Changing foreign table options may affect optimization.
4136  */
4137  case AT_GenericOptions:
4139  cmd_lockmode = AccessExclusiveLock;
4140  break;
4141 
4142  /*
4143  * These subcommands affect write operations only.
4144  */
4145  case AT_EnableTrig:
4146  case AT_EnableAlwaysTrig:
4147  case AT_EnableReplicaTrig:
4148  case AT_EnableTrigAll:
4149  case AT_EnableTrigUser:
4150  case AT_DisableTrig:
4151  case AT_DisableTrigAll:
4152  case AT_DisableTrigUser:
4153  cmd_lockmode = ShareRowExclusiveLock;
4154  break;
4155 
4156  /*
4157  * These subcommands affect write operations only. XXX
4158  * Theoretically, these could be ShareRowExclusiveLock.
4159  */
4160  case AT_ColumnDefault:
4162  case AT_AlterConstraint:
4163  case AT_AddIndex: /* from ADD CONSTRAINT */
4164  case AT_AddIndexConstraint:
4165  case AT_ReplicaIdentity:
4166  case AT_SetNotNull:
4167  case AT_EnableRowSecurity:
4168  case AT_DisableRowSecurity:
4169  case AT_ForceRowSecurity:
4170  case AT_NoForceRowSecurity:
4171  case AT_AddIdentity:
4172  case AT_DropIdentity:
4173  case AT_SetIdentity:
4174  case AT_DropExpression:
4175  case AT_SetCompression:
4176  cmd_lockmode = AccessExclusiveLock;
4177  break;
4178 
4179  case AT_AddConstraint:
4180  case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
4181  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4182  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4183  if (IsA(cmd->def, Constraint))
4184  {
4185  Constraint *con = (Constraint *) cmd->def;
4186 
4187  switch (con->contype)
4188  {
4189  case CONSTR_EXCLUSION:
4190  case CONSTR_PRIMARY:
4191  case CONSTR_UNIQUE:
4192 
4193  /*
4194  * Cases essentially the same as CREATE INDEX. We
4195  * could reduce the lock strength to ShareLock if
4196  * we can work out how to allow concurrent catalog
4197  * updates. XXX Might be set down to
4198  * ShareRowExclusiveLock but requires further
4199  * analysis.
4200  */
4201  cmd_lockmode = AccessExclusiveLock;
4202  break;
4203  case CONSTR_FOREIGN:
4204 
4205  /*
4206  * We add triggers to both tables when we add a
4207  * Foreign Key, so the lock level must be at least
4208  * as strong as CREATE TRIGGER.
4209  */
4210  cmd_lockmode = ShareRowExclusiveLock;
4211  break;
4212 
4213  default:
4214  cmd_lockmode = AccessExclusiveLock;
4215  }
4216  }
4217  break;
4218 
4219  /*
4220  * These subcommands affect inheritance behaviour. Queries
4221  * started before us will continue to see the old inheritance
4222  * behaviour, while queries started after we commit will see
4223  * new behaviour. No need to prevent reads or writes to the
4224  * subtable while we hook it up though. Changing the TupDesc
4225  * may be a problem, so keep highest lock.
4226  */
4227  case AT_AddInherit:
4228  case AT_DropInherit:
4229  cmd_lockmode = AccessExclusiveLock;
4230  break;
4231 
4232  /*
4233  * These subcommands affect implicit row type conversion. They
4234  * have affects similar to CREATE/DROP CAST on queries. don't
4235  * provide for invalidating parse trees as a result of such
4236  * changes, so we keep these at AccessExclusiveLock.
4237  */
4238  case AT_AddOf:
4239  case AT_DropOf:
4240  cmd_lockmode = AccessExclusiveLock;
4241  break;
4242 
4243  /*
4244  * Only used by CREATE OR REPLACE VIEW which must conflict
4245  * with an SELECTs currently using the view.
4246  */
4247  case AT_ReplaceRelOptions:
4248  cmd_lockmode = AccessExclusiveLock;
4249  break;
4250 
4251  /*
4252  * These subcommands affect general strategies for performance
4253  * and maintenance, though don't change the semantic results
4254  * from normal data reads and writes. Delaying an ALTER TABLE
4255  * behind currently active writes only delays the point where
4256  * the new strategy begins to take effect, so there is no
4257  * benefit in waiting. In this case the minimum restriction
4258  * applies: we don't currently allow concurrent catalog
4259  * updates.
4260  */
4261  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4262  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4263  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4264  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4265  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4266  cmd_lockmode = ShareUpdateExclusiveLock;
4267  break;
4268 
4269  case AT_SetLogged:
4270  case AT_SetUnLogged:
4271  cmd_lockmode = AccessExclusiveLock;
4272  break;
4273 
4274  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4275  cmd_lockmode = ShareUpdateExclusiveLock;
4276  break;
4277 
4278  /*
4279  * Rel options are more complex than first appears. Options
4280  * are set here for tables, views and indexes; for historical
4281  * reasons these can all be used with ALTER TABLE, so we can't
4282  * decide between them using the basic grammar.
4283  */
4284  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4285  * getTables() */
4286  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4287  * getTables() */
4288  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4289  break;
4290 
4291  case AT_AttachPartition:
4292  cmd_lockmode = ShareUpdateExclusiveLock;
4293  break;
4294 
4295  case AT_DetachPartition:
4296  if (((PartitionCmd *) cmd->def)->concurrent)
4297  cmd_lockmode = ShareUpdateExclusiveLock;
4298  else
4299  cmd_lockmode = AccessExclusiveLock;
4300  break;
4301 
4303  cmd_lockmode = ShareUpdateExclusiveLock;
4304  break;
4305 
4306  case AT_CheckNotNull:
4307 
4308  /*
4309  * This only examines the table's schema; but lock must be
4310  * strong enough to prevent concurrent DROP NOT NULL.
4311  */
4312  cmd_lockmode = AccessShareLock;
4313  break;
4314 
4315  default: /* oops */
4316  elog(ERROR, "unrecognized alter table type: %d",
4317  (int) cmd->subtype);
4318  break;
4319  }
4320 
4321  /*
4322  * Take the greatest lockmode from any subcommand
4323  */
4324  if (cmd_lockmode > lockmode)
4325  lockmode = cmd_lockmode;
4326  }
4327 
4328  return lockmode;
4329 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
int LOCKMODE
Definition: lockdefs.h:26
#define AccessShareLock
Definition: lockdefs.h:36
AlterTableType subtype
Definition: parsenodes.h:1962
#define ERROR
Definition: elog.h:46
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define lfirst(lc)
Definition: pg_list.h:169
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2102
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define elog(elevel,...)
Definition: elog.h:232
ConstrType contype
Definition: parsenodes.h:2263
Definition: pg_list.h:50

◆ AlterTableInternal()

void AlterTableInternal ( Oid  relid,
List cmds,
bool  recurse 
)

Definition at line 4022 of file tablecmds.c.

References AlterTableGetLockLevel(), ATController(), EventTriggerAlterTableRelid(), and relation_open().

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

4023 {
4024  Relation rel;
4025  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4026 
4027  rel = relation_open(relid, lockmode);
4028 
4030 
4031  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4032 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4338
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4067
void EventTriggerAlterTableRelid(Oid objectId)

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3937 of file tablecmds.c.

References AlterTableStmt::missing_ok, RangeVarCallbackForAlterRelation(), RangeVarGetRelidExtended(), AlterTableStmt::relation, and RVR_MISSING_OK.

Referenced by ProcessUtilitySlow().

3938 {
3939  return RangeVarGetRelidExtended(stmt->relation, lockmode,
3940  stmt->missing_ok ? RVR_MISSING_OK : 0,
3942  (void *) stmt);
3943 }
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:16540
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:237
RangeVar * relation
Definition: parsenodes.h:1871

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 14031 of file tablecmds.c.

References AccessExclusiveLock, AccessShareLock, ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTableInternal(), AT_SetTableSpace, BTEqualStrategyNumber, ConditionalLockRelationOid(), ereport, errcode(), errmsg(), ERROR, EventTriggerAlterTableEnd(), EventTriggerAlterTableStart(), ForwardScanDirection, get_namespace_name(), get_rel_relkind(), get_relkind_objtype(), get_tablespace_name(), get_tablespace_oid(), GETSTRUCT, GetUserId(), heap_getnext(), InvalidOid, isAnyTempNamespace(), IsCatalogNamespace(), IsToastNamespace(), sort-test::key, lappend(), lappend_oid(), lfirst_oid, list_member_oid(), LockRelationOid(), makeNode, MyDatabaseTableSpace, AlterTableCmd::name, NameStr, AlterTableMoveAllStmt::new_tablespacename, NIL, NOTICE, AlterTableMoveAllStmt::nowait, OBJECT_INDEX, OBJECT_MATVIEW, OBJECT_TABLE, OBJECT_TABLESPACE, ObjectIdGetDatum, AlterTableMoveAllStmt::objtype, OidIsValid, AlterTableMoveAllStmt::orig_tablespacename, pg_class_ownercheck(), pg_tablespace_aclcheck(), AlterTableMoveAllStmt::roles, roleSpecsToIds(), ScanKeyInit(), AlterTableCmd::subtype, table_beginscan_catalog(), table_close(), table_endscan(), and table_open().

Referenced by ProcessUtilitySlow().

14032 {
14033  List *relations = NIL;
14034  ListCell *l;
14035  ScanKeyData key[1];
14036  Relation rel;
14037  TableScanDesc scan;
14038  HeapTuple tuple;
14039  Oid orig_tablespaceoid;
14040  Oid new_tablespaceoid;
14041  List *role_oids = roleSpecsToIds(stmt->roles);
14042 
14043  /* Ensure we were not asked to move something we can't */
14044  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
14045  stmt->objtype != OBJECT_MATVIEW)
14046  ereport(ERROR,
14047  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14048  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
14049 
14050  /* Get the orig and new tablespace OIDs */
14051  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
14052  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
14053 
14054  /* Can't move shared relations in to or out of pg_global */
14055  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
14056  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
14057  new_tablespaceoid == GLOBALTABLESPACE_OID)
14058  ereport(ERROR,
14059  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14060  errmsg("cannot move relations in to or out of pg_global tablespace")));
14061 
14062  /*
14063  * Must have CREATE rights on the new tablespace, unless it is the
14064  * database default tablespace (which all users implicitly have CREATE
14065  * rights on).
14066  */
14067  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
14068  {
14069  AclResult aclresult;
14070 
14071  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
14072  ACL_CREATE);
14073  if (aclresult != ACLCHECK_OK)
14074  aclcheck_error(aclresult, OBJECT_TABLESPACE,
14075  get_tablespace_name(new_tablespaceoid));
14076  }
14077 
14078  /*
14079  * Now that the checks are done, check if we should set either to
14080  * InvalidOid because it is our database's default tablespace.
14081  */
14082  if (orig_tablespaceoid == MyDatabaseTableSpace)
14083  orig_tablespaceoid = InvalidOid;
14084 
14085  if (new_tablespaceoid == MyDatabaseTableSpace)
14086  new_tablespaceoid = InvalidOid;
14087 
14088  /* no-op */
14089  if (orig_tablespaceoid == new_tablespaceoid)
14090  return new_tablespaceoid;
14091 
14092  /*
14093  * Walk the list of objects in the tablespace and move them. This will
14094  * only find objects in our database, of course.
14095  */
14096  ScanKeyInit(&key[0],
14097  Anum_pg_class_reltablespace,
14098  BTEqualStrategyNumber, F_OIDEQ,
14099  ObjectIdGetDatum(orig_tablespaceoid));
14100 
14101  rel = table_open(RelationRelationId, AccessShareLock);
14102  scan = table_beginscan_catalog(rel, 1, key);
14103  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
14104  {
14105  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
14106  Oid relOid = relForm->oid;
14107 
14108  /*
14109  * Do not move objects in pg_catalog as part of this, if an admin
14110  * really wishes to do so, they can issue the individual ALTER
14111  * commands directly.
14112  *
14113  * Also, explicitly avoid any shared tables, temp tables, or TOAST
14114  * (TOAST will be moved with the main table).
14115  */
14116  if (IsCatalogNamespace(relForm->relnamespace) ||
14117  relForm->relisshared ||
14118  isAnyTempNamespace(relForm->relnamespace) ||
14119  IsToastNamespace(relForm->relnamespace))
14120  continue;
14121 
14122  /* Only move the object type requested */
14123  if ((stmt->objtype == OBJECT_TABLE &&
14124  relForm->relkind != RELKIND_RELATION &&
14125  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
14126  (stmt->objtype == OBJECT_INDEX &&
14127  relForm->relkind != RELKIND_INDEX &&
14128  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
14129  (stmt->objtype == OBJECT_MATVIEW &&
14130  relForm->relkind != RELKIND_MATVIEW))
14131  continue;
14132 
14133  /* Check if we are only moving objects owned by certain roles */
14134  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
14135  continue;
14136 
14137  /*
14138  * Handle permissions-checking here since we are locking the tables
14139  * and also to avoid doing a bunch of work only to fail part-way. Note
14140  * that permissions will also be checked by AlterTableInternal().
14141  *
14142  * Caller must be considered an owner on the table to move it.
14143  */
14144  if (!pg_class_ownercheck(relOid, GetUserId()))
14146  NameStr(relForm->relname));
14147 
14148  if (stmt->nowait &&
14150  ereport(ERROR,
14151  (errcode(ERRCODE_OBJECT_IN_USE),
14152  errmsg("aborting because lock on relation \"%s.%s\" is not available",
14153  get_namespace_name(relForm->relnamespace),
14154  NameStr(relForm->relname))));
14155  else
14157 
14158  /* Add to our list of objects to move */
14159  relations = lappend_oid(relations, relOid);
14160  }
14161 
14162  table_endscan(scan);
14164 
14165  if (relations == NIL)
14166  ereport(NOTICE,
14167  (errcode(ERRCODE_NO_DATA_FOUND),
14168  errmsg("no matching relations in tablespace \"%s\" found",
14169  orig_tablespaceoid == InvalidOid ? "(database default)" :
14170  get_tablespace_name(orig_tablespaceoid))));
14171 
14172  /* Everything is locked, loop through and move all of the relations. */
14173  foreach(l, relations)
14174  {
14175  List *cmds = NIL;
14177 
14178  cmd->subtype = AT_SetTableSpace;
14179  cmd->name = stmt->new_tablespacename;
14180 
14181  cmds = lappend(cmds, cmd);
14182 
14184  /* OID is set by AlterTableInternal */
14185  AlterTableInternal(lfirst_oid(l), cmds, false);
14187  }
14188 
14189  return new_tablespaceoid;
14190 }
#define NIL
Definition: pg_list.h:65
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:152
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1427
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4768
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
Oid GetUserId(void)
Definition: miscinit.c:495
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1974
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:536
int errcode(int sqlerrcode)
Definition: elog.c:698
AlterTableType subtype
Definition: parsenodes.h:1962
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:201
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
#define OidIsValid(objectId)
Definition: c.h:710
Oid MyDatabaseTableSpace
Definition: globals.c:90
void EventTriggerAlterTableStart(Node *parsetree)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3308
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define ACL_CREATE
Definition: parsenodes.h:92
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1340
List * lappend(List *list, void *datum)
Definition: list.c:336
AclResult
Definition: acl.h:177
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:584
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1376
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:689
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4818
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:183
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:991
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4022
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:909
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1473
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:681
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3240
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:109
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:171
void EventTriggerAlterTableEnd(void)

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 15916 of file tablecmds.c.

References AccessExclusiveLock, AlterTableNamespaceInternal(), CheckSetNamespace(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, ereport, errcode(), errdetail(), errmsg(), ERROR, free_object_addresses(), get_rel_name(), InvalidObjectAddress, makeRangeVar(), AlterObjectSchemaStmt::missing_ok, new_object_addresses(), NoLock, NOTICE, ObjectAddressSet, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelidExtended(), RelationData::rd_rel, AlterObjectSchemaStmt::relation, relation_close(), relation_open(), RelationGetNamespace, RelationGetRelationName, OnCommitItem::relid, RVR_MISSING_OK, and sequenceIsOwned().

Referenced by ExecAlterObjectSchemaStmt().

15917 {
15918  Relation rel;
15919  Oid relid;
15920  Oid oldNspOid;
15921  Oid nspOid;
15922  RangeVar *newrv;
15923  ObjectAddresses *objsMoved;
15924  ObjectAddress myself;
15925 
15927  stmt->missing_ok ? RVR_MISSING_OK : 0,
15929  (void *) stmt);
15930 
15931  if (!OidIsValid(relid))
15932  {
15933  ereport(NOTICE,
15934  (errmsg("relation \"%s\" does not exist, skipping",
15935  stmt->relation->relname)));
15936  return InvalidObjectAddress;
15937  }
15938 
15939  rel = relation_open(relid, NoLock);
15940 
15941  oldNspOid = RelationGetNamespace(rel);
15942 
15943  /* If it's an owned sequence, disallow moving it by itself. */
15944  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
15945  {
15946  Oid tableId;
15947  int32 colId;
15948 
15949  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
15950  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
15951  ereport(ERROR,
15952  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15953  errmsg("cannot move an owned sequence into another schema"),
15954  errdetail("Sequence \"%s\" is linked to table \"%s\".",
15956  get_rel_name(tableId))));
15957  }
15958 
15959  /* Get and lock schema OID and check its permissions. */
15960  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
15961  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
15962 
15963  /* common checks on switching namespaces */
15964  CheckSetNamespace(oldNspOid, nspOid);
15965 
15966  objsMoved = new_object_addresses();
15967  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
15968  free_object_addresses(objsMoved);
15969 
15970  ObjectAddressSet(myself, RelationRelationId, relid);
15971 
15972  if (oldschema)
15973  *oldschema = oldNspOid;
15974 
15975  /* close rel, but keep lock until commit */
15976  relation_close(rel, NoLock);
15977 
15978  return myself;
15979 }
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:770
int errcode(int sqlerrcode)
Definition: elog.c:698
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2430
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2725
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
signed int int32
Definition: c.h:429
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:46
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15987
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:16540
int errdetail(const char *fmt,...)
Definition: elog.c:1042
#define RelationGetRelationName(relation)
Definition: rel.h:511
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:237
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3012
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:535
#define ereport(elevel,...)
Definition: elog.h:157
#define NOTICE
Definition: elog.h:37
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:909
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1899
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:422
#define RelationGetNamespace(relation)
Definition: rel.h:518

◆ AlterTableNamespaceInternal()

void AlterTableNamespaceInternal ( Relation  rel,
Oid  oldNspOid,
Oid  nspOid,
ObjectAddresses objsMoved 
)

Definition at line 15987 of file tablecmds.c.

References AccessExclusiveLock, AlterConstraintNamespaces(), AlterIndexNamespaces(), AlterRelationNamespaceInternal(), AlterSeqNamespaces(), AlterTypeNamespaceInternal(), Assert, OidIsValid, RelationData::rd_rel, RelationGetRelid, RowExclusiveLock, table_close(), and table_open().

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

15989 {
15990  Relation classRel;
15991 
15992  Assert(objsMoved != NULL);
15993 
15994  /* OK, modify the pg_class row and pg_depend entry */
15995  classRel = table_open(RelationRelationId, RowExclusiveLock);
15996 
15997  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
15998  nspOid, true, objsMoved);
15999 
16000  /* Fix the table's row type too, if it has one */
16001  if (OidIsValid(rel->rd_rel->reltype))
16002  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
16003  nspOid, false, false, objsMoved);
16004 
16005  /* Fix other dependent stuff */
16006  if (rel->rd_rel->relkind == RELKIND_RELATION ||
16007  rel->rd_rel->relkind == RELKIND_MATVIEW ||
16008  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16009  {
16010  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
16011  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
16012  objsMoved, AccessExclusiveLock);
16013  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
16014  false, objsMoved);
16015  }
16016 
16017  table_close(classRel, RowExclusiveLock);
16018 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3955
Form_pg_class rd_rel
Definition: rel.h:109
#define OidIsValid(objectId)
Definition: c.h:710
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16096
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:16141
#define RowExclusiveLock
Definition: lockdefs.h:38
#define Assert(condition)
Definition: c.h:804
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16026
#define AccessExclusiveLock
Definition: lockdefs.h:45
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:477

◆ AtEOSubXact_on_commit_actions()

void AtEOSubXact_on_commit_actions ( bool  isCommit,
SubTransactionId  mySubid,
SubTransactionId  parentSubid 
)

Definition at line 16417 of file tablecmds.c.

References OnCommitItem::creating_subid, OnCommitItem::deleting_subid, foreach_delete_current, InvalidSubTransactionId, lfirst, and pfree().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

16419 {
16420  ListCell *cur_item;
16421 
16422  foreach(cur_item, on_commits)
16423  {
16424  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16425 
16426  if (!isCommit && oc->creating_subid == mySubid)
16427  {
16428  /* cur_item must be removed */
16430  pfree(oc);
16431  }
16432  else
16433  {
16434  /* cur_item must be preserved */
16435  if (oc->creating_subid == mySubid)
16436  oc->creating_subid = parentSubid;
16437  if (oc->deleting_subid == mySubid)
16438  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
16439  }
16440  }
16441 }
SubTransactionId creating_subid
Definition: tablecmds.c:119
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
void pfree(void *pointer)
Definition: mcxt.c:1169
static List * on_commits
Definition: tablecmds.c:123
SubTransactionId deleting_subid
Definition: tablecmds.c:120
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:593

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 16385 of file tablecmds.c.

References OnCommitItem::creating_subid, OnCommitItem::deleting_subid, foreach_delete_current, InvalidSubTransactionId, lfirst, and pfree().

Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().

16386 {
16387  ListCell *cur_item;
16388 
16389  foreach(cur_item, on_commits)
16390  {
16391  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16392 
16393  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
16395  {
16396  /* cur_item must be removed */
16398  pfree(oc);
16399  }
16400  else
16401  {
16402  /* cur_item must be preserved */
16405  }
16406  }
16407 }
SubTransactionId creating_subid
Definition: tablecmds.c:119
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
void pfree(void *pointer)
Definition: mcxt.c:1169
static List * on_commits
Definition: tablecmds.c:123
SubTransactionId deleting_subid
Definition: tablecmds.c:120
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:593

◆ ATExecChangeOwner()

void ATExecChangeOwner ( Oid  relationOid,
Oid  newOwnerId,
bool  recursing,
LOCKMODE  lockmode 
)

Definition at line 13228 of file tablecmds.c.

References ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, aclnewowner(), AlterTypeOwnerInternal(), ATExecChangeOwner(), CatalogTupleUpdate(), change_owner_fix_column_acls(), change_owner_recurse_to_sequences(), changeDependencyOnOwner(), check_is_member_of_role(), DatumGetAclP, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, elog, ereport, errcode(), errdetail(), errdetail_relkind_not_supported(), errhint(), errmsg(), ERROR, get_namespace_name(), get_rel_name(), get_rel_relkind(), get_relkind_objtype(), GETSTRUCT, GetUserId(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, i, InvalidOid, InvokeObjectPostAlterHook, lfirst_oid, list_free(), NameStr, NoLock, OBJECT_SCHEMA, ObjectIdGetDatum, OidIsValid, pg_class_ownercheck(), pg_namespace_aclcheck(), PointerGetDatum, relation_close(), relation_open(), RelationGetDescr, RelationGetIndexList(), RelationGetRelationName, ReleaseSysCache(), RELOID, RowExclusiveLock, SearchSysCache1(), sequenceIsOwned(), superuser(), SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), and WARNING.

Referenced by AlterTypeOwner_oid(), ATExecChangeOwner(), ATExecCmd(), change_owner_recurse_to_sequences(), and shdepReassignOwned().

13229 {
13230  Relation target_rel;
13231  Relation class_rel;
13232  HeapTuple tuple;
13233  Form_pg_class tuple_class;
13234 
13235  /*
13236  * Get exclusive lock till end of transaction on the target table. Use
13237  * relation_open so that we can work on indexes and sequences.
13238  */
13239  target_rel = relation_open(relationOid, lockmode);
13240 
13241  /* Get its pg_class tuple, too */
13242  class_rel = table_open(RelationRelationId, RowExclusiveLock);
13243 
13244  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
13245  if (!HeapTupleIsValid(tuple))
13246  elog(ERROR, "cache lookup failed for relation %u", relationOid);
13247  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
13248 
13249  /* Can we change the ownership of this tuple? */
13250  switch (tuple_class->relkind)
13251  {
13252  case RELKIND_RELATION:
13253  case RELKIND_VIEW:
13254  case RELKIND_MATVIEW:
13255  case RELKIND_FOREIGN_TABLE:
13256  case RELKIND_PARTITIONED_TABLE:
13257  /* ok to change owner */
13258  break;
13259  case RELKIND_INDEX:
13260  if (!recursing)
13261  {
13262  /*
13263  * Because ALTER INDEX OWNER used to be allowed, and in fact
13264  * is generated by old versions of pg_dump, we give a warning
13265  * and do nothing rather than erroring out. Also, to avoid
13266  * unnecessary chatter while restoring those old dumps, say
13267  * nothing at all if the command would be a no-op anyway.
13268  */
13269  if (tuple_class->relowner != newOwnerId)
13270  ereport(WARNING,
13271  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13272  errmsg("cannot change owner of index \"%s\"",
13273  NameStr(tuple_class->relname)),
13274  errhint("Change the ownership of the index's table, instead.")));
13275  /* quick hack to exit via the no-op path */
13276  newOwnerId = tuple_class->relowner;
13277  }
13278  break;
13279  case RELKIND_PARTITIONED_INDEX:
13280  if (recursing)
13281  break;
13282  ereport(ERROR,
13283  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13284  errmsg("cannot change owner of index \"%s\"",
13285  NameStr(tuple_class->relname)),
13286  errhint("Change the ownership of the index's table, instead.")));
13287  break;
13288  case RELKIND_SEQUENCE:
13289  if (!recursing &&
13290  tuple_class->relowner != newOwnerId)
13291  {
13292  /* if it's an owned sequence, disallow changing it by itself */
13293  Oid tableId;
13294  int32 colId;
13295 
13296  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
13297  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
13298  ereport(ERROR,
13299  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13300  errmsg("cannot change owner of sequence \"%s\"",
13301  NameStr(tuple_class->relname)),
13302  errdetail("Sequence \"%s\" is linked to table \"%s\".",
13303  NameStr(tuple_class->relname),
13304  get_rel_name(tableId))));
13305  }
13306  break;
13307  case RELKIND_COMPOSITE_TYPE:
13308  if (recursing)
13309  break;
13310  ereport(ERROR,
13311  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13312  errmsg("\"%s\" is a composite type",
13313  NameStr(tuple_class->relname)),
13314  errhint("Use ALTER TYPE instead.")));
13315  break;
13316  case RELKIND_TOASTVALUE:
13317  if (recursing)
13318  break;
13319  /* FALL THRU */
13320  default:
13321  ereport(ERROR,
13322  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13323  errmsg("cannot change owner of relation \"%s\"",
13324  NameStr(tuple_class->relname)),
13325  errdetail_relkind_not_supported(tuple_class->relkind)));
13326  }
13327 
13328  /*
13329  * If the new owner is the same as the existing owner, consider the
13330  * command to have succeeded. This is for dump restoration purposes.
13331  */
13332  if (tuple_class->relowner != newOwnerId)
13333  {
13334  Datum repl_val[Natts_pg_class];
13335  bool repl_null[Natts_pg_class];
13336  bool repl_repl[Natts_pg_class];
13337  Acl *newAcl;
13338  Datum aclDatum;
13339  bool isNull;
13340  HeapTuple newtuple;
13341 
13342  /* skip permission checks when recursing to index or toast table */
13343  if (!recursing)
13344  {
13345  /* Superusers can always do it */
13346  if (!superuser())
13347  {
13348  Oid namespaceOid = tuple_class->relnamespace;
13349  AclResult aclresult;
13350 
13351  /* Otherwise, must be owner of the existing object */
13352  if (!pg_class_ownercheck(relationOid, GetUserId()))
13354  RelationGetRelationName(target_rel));
13355 
13356  /* Must be able to become new owner */
13357  check_is_member_of_role(GetUserId(), newOwnerId);
13358 
13359  /* New owner must have CREATE privilege on namespace */
13360  aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
13361  ACL_CREATE);
13362  if (aclresult != ACLCHECK_OK)
13363  aclcheck_error(aclresult, OBJECT_SCHEMA,
13364  get_namespace_name(namespaceOid));
13365  }
13366  }
13367 
13368  memset(repl_null, false, sizeof(repl_null));
13369  memset(repl_repl, false, sizeof(repl_repl));
13370 
13371  repl_repl[Anum_pg_class_relowner - 1] = true;
13372  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
13373 
13374  /*
13375  * Determine the modified ACL for the new owner. This is only
13376  * necessary when the ACL is non-null.
13377  */
13378  aclDatum = SysCacheGetAttr(RELOID, tuple,
13379  Anum_pg_class_relacl,
13380  &isNull);
13381  if (!isNull)
13382  {
13383  newAcl = aclnewowner(DatumGetAclP(aclDatum),
13384  tuple_class->relowner, newOwnerId);
13385  repl_repl[Anum_pg_class_relacl - 1] = true;
13386  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
13387  }
13388 
13389  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
13390 
13391  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
13392 
13393  heap_freetuple(newtuple);
13394 
13395  /*
13396  * We must similarly update any per-column ACLs to reflect the new
13397  * owner; for neatness reasons that's split out as a subroutine.
13398  */
13399  change_owner_fix_column_acls(relationOid,
13400  tuple_class->relowner,
13401  newOwnerId);
13402 
13403  /*
13404  * Update owner dependency reference, if any. A composite type has
13405  * none, because it's tracked for the pg_type entry instead of here;
13406  * indexes and TOAST tables don't have their own entries either.
13407  */
13408  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
13409  tuple_class->relkind != RELKIND_INDEX &&
13410  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
13411  tuple_class->relkind != RELKIND_TOASTVALUE)
13412  changeDependencyOnOwner(RelationRelationId, relationOid,
13413  newOwnerId);
13414 
13415  /*
13416  * Also change the ownership of the table's row type, if it has one
13417  */
13418  if (OidIsValid(tuple_class->reltype))
13419  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
13420 
13421  /*
13422  * If we are operating on a table or materialized view, also change
13423  * the ownership of any indexes and sequences that belong to the
13424  * relation, as well as its toast table (if it has one).
13425  */
13426  if (tuple_class->relkind == RELKIND_RELATION ||
13427  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
13428  tuple_class->relkind == RELKIND_MATVIEW ||
13429  tuple_class->relkind == RELKIND_TOASTVALUE)
13430  {
13431  List *index_oid_list;
13432  ListCell *i;
13433 
13434  /* Find all the indexes belonging to this relation */
13435  index_oid_list = RelationGetIndexList(target_rel);
13436 
13437  /* For each index, recursively change its ownership */
13438  foreach(i, index_oid_list)
13439  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
13440 
13441  list_free(index_oid_list);
13442  }
13443 
13444  /* If it has a toast table, recurse to change its ownership */
13445  if (tuple_class->reltoastrelid != InvalidOid)
13446  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
13447  true, lockmode);
13448 
13449  /* If it has dependent sequences, recurse to change them too */
13450  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
13451  }
13452 
13453  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
13454 
13455  ReleaseSysCache(tuple);
13456  table_close(class_rel, RowExclusiveLock);
13457  relation_close(target_rel, NoLock);
13458 }
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int errhint(const char *fmt,...)
Definition: elog.c:1156
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:770
#define RelationGetDescr(relation)
Definition: rel.h:503
Oid GetUserId(void)
Definition: miscinit.c:495
#define DatumGetAclP(X)
Definition: acl.h:120
#define PointerGetDatum(X)
Definition: postgres.h:600
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1974
int errcode(int sqlerrcode)
Definition: elog.c:698
bool superuser(void)
Definition: superuser.c:46
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3825
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4756
signed int int32
Definition: c.h:429
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:311
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3308
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define ACL_CREATE
Definition: parsenodes.h:92
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:1042
#define RelationGetRelationName(relation)
Definition: rel.h:511
void check_is_member_of_role(Oid member, Oid role)
Definition: acl.c:4893
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:13228
#define WARNING
Definition: elog.h:40
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:411
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1388
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4818
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:13532
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4573
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:13467
int errmsg(const char *fmt,...)
Definition: elog.c:909
void list_free(List *list)
Definition: list.c:1391
#define elog(elevel,...)
Definition: elog.h:232
int i
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:681
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
Definition: pg_list.h:50
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1899
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1037
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ check_of_type()

void check_of_type ( HeapTuple  typetuple)

Definition at line 6476 of file tablecmds.c.

References AccessShareLock, Assert, ereport, errcode(), errmsg(), ERROR, format_type_be(), GETSTRUCT, NoLock, OidIsValid, RelationData::rd_rel, relation_close(), and relation_open().

Referenced by ATExecAddOf(), and transformOfType().

6477 {
6478  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
6479  bool typeOk = false;
6480 
6481  if (typ->typtype == TYPTYPE_COMPOSITE)
6482  {
6483  Relation typeRelation;
6484 
6485  Assert(OidIsValid(typ->typrelid));
6486  typeRelation = relation_open(typ->typrelid, AccessShareLock);
6487  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6488 
6489  /*
6490  * Close the parent rel, but keep our AccessShareLock on it until xact
6491  * commit. That will prevent someone else from deleting or ALTERing
6492  * the type before the typed table creation/conversion commits.
6493  */
6494  relation_close(typeRelation, NoLock);
6495  }
6496  if (!typeOk)
6497  ereport(ERROR,
6498  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6499  errmsg("type %s is not a composite type",
6500  format_type_be(typ->oid))));
6501 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:698
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Form_pg_class rd_rel
Definition: rel.h:109
#define OidIsValid(objectId)
Definition: c.h:710
#define ERROR
Definition: elog.h:46
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
#define ereport(elevel,...)
Definition: elog.h:157
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:804
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
int errmsg(const char *fmt,...)
Definition: elog.c:909

◆ CheckRelationTableSpaceMove()

bool CheckRelationTableSpaceMove ( Relation  rel,
Oid  newTableSpaceId 
)

Definition at line 3228 of file tablecmds.c.

References ereport, errcode(), errmsg(), ERROR, MyDatabaseTableSpace, RelationData::rd_rel, RELATION_IS_OTHER_TEMP, RelationGetRelationName, and RelationIsMapped.

Referenced by ATExecSetTableSpace(), ATExecSetTableSpaceNoStorage(), reindex_index(), and SetRelationTableSpace().

3229 {
3230  Oid oldTableSpaceId;
3231 
3232  /*
3233  * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3234  * stored as 0.
3235  */
3236  oldTableSpaceId = rel->rd_rel->reltablespace;
3237  if (newTableSpaceId == oldTableSpaceId ||
3238  (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3239  return false;
3240 
3241  /*
3242  * We cannot support moving mapped relations into different tablespaces.
3243  * (In particular this eliminates all shared catalogs.)
3244  */
3245  if (RelationIsMapped(rel))
3246  ereport(ERROR,
3247  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3248  errmsg("cannot move system relation \"%s\"",
3249  RelationGetRelationName(rel))));
3250 
3251  /* Cannot move a non-shared relation into pg_global */
3252  if (newTableSpaceId == GLOBALTABLESPACE_OID)
3253  ereport(ERROR,
3254  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3255  errmsg("only shared relations can be placed in pg_global tablespace")));
3256 
3257  /*
3258  * Do not allow moving temp tables of other backends ... their local
3259  * buffer manager is not going to cope.
3260  */
3261  if (RELATION_IS_OTHER_TEMP(rel))
3262  ereport(ERROR,
3263  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3264  errmsg("cannot move temporary tables of other sessions")));
3265 
3266  return true;
3267 }
int errcode(int sqlerrcode)
Definition: elog.c:698
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
Oid MyDatabaseTableSpace
Definition: globals.c:90
#define ERROR
Definition: elog.h:46
#define RelationGetRelationName(relation)
Definition: rel.h:511
#define RelationIsMapped(relation)
Definition: rel.h:526
#define ereport(elevel,...)
Definition: elog.h:157
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:631
int errmsg(const char *fmt,...)
Definition: elog.c:909

◆ CheckTableNotInUse()

void CheckTableNotInUse ( Relation  rel,
const char *  stmt 
)

Definition at line 3909 of file tablecmds.c.

References AfterTriggerPendingOnRel(), ereport, errcode(), errmsg(), ERROR, RelationData::rd_isnailed, RelationData::rd_refcnt, RelationData::rd_rel, RelationGetRelationName, and RelationGetRelid.

Referenced by addFkRecurseReferencing(), AlterTable(), ATAddCheckConstraint(), ATCheckPartitionsNotInUse(), ATExecAddColumn(), ATExecDropColumn(), ATExecDropConstraint(), ATPrepAlterColumnType(), ATSimpleRecursion(), ATTypedTableRecursion(), cluster_rel(), DefineIndex(), DefineVirtualRelation(), ExecRefreshMatView(), heap_drop_with_catalog(), index_drop(), MergeAttributes(), reindex_index(), and truncate_check_activity().

3910 {
3911  int expected_refcnt;
3912 
3913  expected_refcnt = rel->rd_isnailed ? 2 : 1;
3914  if (rel->rd_refcnt != expected_refcnt)
3915  ereport(ERROR,
3916  (errcode(ERRCODE_OBJECT_IN_USE),
3917  /* translator: first %s is a SQL command, eg ALTER TABLE */
3918  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
3919  stmt, RelationGetRelationName(rel))));
3920 
3921  if (rel->rd_rel->relkind != RELKIND_INDEX &&
3922  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
3924  ereport(ERROR,
3925  (errcode(ERRCODE_OBJECT_IN_USE),
3926  /* translator: first %s is a SQL command, eg ALTER TABLE */
3927  errmsg("cannot %s \"%s\" because it has pending trigger events",
3928  stmt, RelationGetRelationName(rel))));
3929 }
bool rd_isnailed
Definition: rel.h:61
int errcode(int sqlerrcode)
Definition: elog.c:698
Form_pg_class rd_rel
Definition: rel.h:109
#define ERROR
Definition: elog.h:46
#define RelationGetRelationName(relation)
Definition: rel.h:511
#define ereport(elevel,...)
Definition: elog.h:157
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5527
int errmsg(const char *fmt,...)
Definition: elog.c:909
int rd_refcnt
Definition: rel.h:58
#define RelationGetRelid(relation)
Definition: rel.h:477

◆ DefineRelation()

ObjectAddress DefineRelation ( CreateStmt stmt,
char  relkind,
Oid  ownerId,
ObjectAddress typaddress,
const char *  queryString 
)

Definition at line 627 of file tablecmds.c.

References AccessExclusiveLock, CreateStmt::accessMethod, AccessShareLock, ACL_CREATE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, addNSItemToQuery(), addRangeTableEntryForRelation(), AddRelationNewConstraints(), allowSystemTableMods, Assert, RawColumnDefault::attnum, CookedConstraint::attnum, attnum, build_attrmap_by_name(), BuildDescForRelation(), check_default_partition_contents(), check_new_partition_bound(), CloneForeignKeyConstraints(), CloneRowTriggersToPartition(), CommandCounterIncrement(), ColumnDef::compression, ComputePartitionAttrs(), CookedConstraint::conoid, CONSTR_DEFAULT, CreateStmt::constraints, CookedConstraint::contype, ColumnDef::cooked_default, default_table_access_method, DefineIndex(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, CookedConstraint::expr, generateClonedIndexStmt(), RawColumnDefault::generated, ColumnDef::generated, get_default_oid_from_partdesc(), get_rel_name(), get_rel_tablespace(), get_table_am_oid(), get_tablespace_name(), get_tablespace_oid(), GetAttributeCompression(), GetDefaultTablespace(), GetUserId(), heap_create_with_catalog(), HEAP_RELOPT_NAMESPACES, heap_reloptions(), ColumnDef::identity, index_close(), index_open(), CookedConstraint::inhcount, CreateStmt::inhRelations, InSecurityRestrictedOperation(), InvalidOid, CookedConstraint::is_local, CookedConstraint::is_no_inherit, lappend(), lappend_oid(), lfirst, lfirst_oid, linitial_oid, list_concat(), list_free(), list_length(), list_member_oid(), make_parsestate(), MergeAttributes(), RawColumnDefault::missingMode, MyDatabaseTableSpace, CookedConstraint::name, NAMEDATALEN, NIL, NoLock, OBJECT_TABLESPACE, ObjectAddressSet, CreateStmt::ofTypename, OidIsValid, CreateStmt::oncommit, ONCOMMIT_NOOP, CreateStmt::options, ParseState::p_sourcetext, palloc(), CreateStmt::partbound, PARTITION_MAX_KEYS, partitioned_table_reloptions(), PartitionSpec::partParams, CreateStmt::partspec, pg_tablespace_aclcheck(), pg_type_aclcheck(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelid, RawColumnDefault::raw_default, ColumnDef::raw_default, RelationData::rd_index, RelationData::rd_rel, CreateStmt::relation, relation_close(), relation_open(), RelationGetDescr, RelationGetIndexList(), RelationGetPartitionDesc(), RelationGetRelationName, RelationGetRelid, relname, RangeVar::relname, RangeVar::relpersistence, ShareUpdateExclusiveLock, CookedConstraint::skip_validation, StoreCatalogInheritance(), StorePartitionBound(), StorePartitionKey(), strlcpy(), table_close(), table_open(), CreateStmt::tableElts, CreateStmt::tablespacename, transformPartitionBound(), transformPartitionSpec(), transformRelOptions(), RelationData::trigdesc, TupleDescAttr, typenameTypeId(), and view_reloptions().

Referenced by create_ctas_internal(), DefineCompositeType(), DefineSequence(), DefineVirtualRelation(), and ProcessUtilitySlow().

629 {
630  char relname[NAMEDATALEN];
631  Oid namespaceId;
632  Oid relationId;
633  Oid tablespaceId;
634  Relation rel;
636  List *inheritOids;
637  List *old_constraints;
638  List *rawDefaults;
639  List *cookedDefaults;
640  Datum reloptions;
641  ListCell *listptr;
643  bool partitioned;
644  static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
645  Oid ofTypeId;
646  ObjectAddress address;
647  LOCKMODE parentLockmode;
648  const char *accessMethod = NULL;
649  Oid accessMethodId = InvalidOid;
650 
651  /*
652  * Truncate relname to appropriate length (probably a waste of time, as
653  * parser should have done this already).
654  */
655  strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
656 
657  /*
658  * Check consistency of arguments
659  */
660  if (stmt->oncommit != ONCOMMIT_NOOP
661  && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
662  ereport(ERROR,
663  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
664  errmsg("ON COMMIT can only be used on temporary tables")));
665 
666  if (stmt->partspec != NULL)
667  {
668  if (relkind != RELKIND_RELATION)
669  elog(ERROR, "unexpected relkind: %d", (int) relkind);
670 
671  relkind = RELKIND_PARTITIONED_TABLE;
672  partitioned = true;
673  }
674  else
675  partitioned = false;
676 
677  /*
678  * Look up the namespace in which we are supposed to create the relation,
679  * check we have permission to create there, lock it against concurrent
680  * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
681  * namespace is selected.
682  */
683  namespaceId =
685 
686  /*
687  * Security check: disallow creating temp tables from security-restricted
688  * code. This is needed because calling code might not expect untrusted
689  * tables to appear in pg_temp at the front of its search path.
690  */
691  if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
693  ereport(ERROR,
694  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
695  errmsg("cannot create temporary table within security-restricted operation")));
696 
697  /*
698  * Determine the lockmode to use when scanning parents. A self-exclusive
699  * lock is needed here.
700  *
701  * For regular inheritance, if two backends attempt to add children to the
702  * same parent simultaneously, and that parent has no pre-existing
703  * children, then both will attempt to update the parent's relhassubclass
704  * field, leading to a "tuple concurrently updated" error. Also, this
705  * interlocks against a concurrent ANALYZE on the parent table, which
706  * might otherwise be attempting to clear the parent's relhassubclass
707  * field, if its previous children were recently dropped.
708  *
709  * If the child table is a partition, then we instead grab an exclusive
710  * lock on the parent because its partition descriptor will be changed by
711  * addition of the new partition.
712  */
713  parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
715 
716  /* Determine the list of OIDs of the parents. */
717  inheritOids = NIL;
718  foreach(listptr, stmt->inhRelations)
719  {
720  RangeVar *rv = (RangeVar *) lfirst(listptr);
721  Oid parentOid;
722 
723  parentOid = RangeVarGetRelid(rv, parentLockmode, false);
724 
725  /*
726  * Reject duplications in the list of parents.
727  */
728  if (list_member_oid(inheritOids, parentOid))
729  ereport(ERROR,
730  (errcode(ERRCODE_DUPLICATE_TABLE),
731  errmsg("relation \"%s\" would be inherited from more than once",
732  get_rel_name(parentOid))));
733 
734  inheritOids = lappend_oid(inheritOids, parentOid);
735  }
736 
737  /*
738  * Select tablespace to use: an explicitly indicated one, or (in the case
739  * of a partitioned table) the parent's, if it has one.
740  */
741  if (stmt->tablespacename)
742  {
743  tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
744 
745  if (partitioned && tablespaceId == MyDatabaseTableSpace)
746  ereport(ERROR,
747  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
748  errmsg("cannot specify default tablespace for partitioned relations")));
749  }
750  else if (stmt->partbound)
751  {
752  /*
753  * For partitions, when no other tablespace is specified, we default
754  * the tablespace to the parent partitioned table's.
755  */
756  Assert(list_length(inheritOids) == 1);
757  tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
758  }
759  else
760  tablespaceId = InvalidOid;
761 
762  /* still nothing? use the default */
763  if (!OidIsValid(tablespaceId))
764  tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
765  partitioned);
766 
767  /* Check permissions except when using database's default */
768  if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
769  {
770  AclResult aclresult;
771 
772  aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
773  ACL_CREATE);
774  if (aclresult != ACLCHECK_OK)
776  get_tablespace_name(tablespaceId));
777  }
778 
779  /* In all cases disallow placing user relations in pg_global */
780  if (tablespaceId == GLOBALTABLESPACE_OID)
781  ereport(ERROR,
782  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
783  errmsg("only shared relations can be placed in pg_global tablespace")));
784 
785  /* Identify user ID that will own the table */
786  if (!OidIsValid(ownerId))
787  ownerId = GetUserId();
788 
789  /*
790  * Parse and validate reloptions, if any.
791  */
792  reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
793  true, false);
794 
795  switch (relkind)
796  {
797  case RELKIND_VIEW:
798  (void) view_reloptions(reloptions, true);
799  break;
800  case RELKIND_PARTITIONED_TABLE:
801  (void) partitioned_table_reloptions(reloptions, true);
802  break;
803  default:
804  (void) heap_reloptions(relkind, reloptions, true);
805  }
806 
807  if (stmt->ofTypename)
808  {
809  AclResult aclresult;
810 
811  ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
812 
813  aclresult = pg_type_aclcheck(ofTypeId, GetUserId(), ACL_USAGE);
814  if (aclresult != ACLCHECK_OK)
815  aclcheck_error_type(aclresult, ofTypeId);
816  }
817  else
818  ofTypeId = InvalidOid;
819 
820  /*
821  * Look up inheritance ancestors and generate relation schema, including
822  * inherited attributes. (Note that stmt->tableElts is destructively
823  * modified by MergeAttributes.)
824  */
825  stmt->tableElts =
826  MergeAttributes(stmt->tableElts, inheritOids,
827  stmt->relation->relpersistence,
828  stmt->partbound != NULL,
829  &old_constraints);
830 
831  /*
832  * Create a tuple descriptor from the relation schema. Note that this
833  * deals with column names, types, and NOT NULL constraints, but not
834  * default values or CHECK constraints; we handle those below.
835  */
836  descriptor = BuildDescForRelation(stmt->tableElts);
837 
838  /*
839  * Find columns with default values and prepare for insertion of the
840  * defaults. Pre-cooked (that is, inherited) defaults go into a list of
841  * CookedConstraint structs that we'll pass to heap_create_with_catalog,
842  * while raw defaults go into a list of RawColumnDefault structs that will
843  * be processed by AddRelationNewConstraints. (We can't deal with raw
844  * expressions until we can do transformExpr.)
845  *
846  * We can set the atthasdef flags now in the tuple descriptor; this just
847  * saves StoreAttrDefault from having to do an immediate update of the
848  * pg_attribute rows.
849  */
850  rawDefaults = NIL;
851  cookedDefaults = NIL;
852  attnum = 0;
853 
854  foreach(listptr, stmt->tableElts)
855  {
856  ColumnDef *colDef = lfirst(listptr);
857  Form_pg_attribute attr;
858 
859  attnum++;
860  attr = TupleDescAttr(descriptor, attnum - 1);
861 
862  if (colDef->raw_default != NULL)
863  {
864  RawColumnDefault *rawEnt;
865 
866  Assert(colDef->cooked_default == NULL);
867 
868  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
869  rawEnt->attnum = attnum;
870  rawEnt->raw_default = colDef->raw_default;
871  rawEnt->missingMode = false;
872  rawEnt->generated = colDef->generated;
873  rawDefaults = lappend(rawDefaults, rawEnt);
874  attr->atthasdef = true;
875  }
876  else if (colDef->cooked_default != NULL)
877  {
878  CookedConstraint *cooked;
879 
880  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
881  cooked->contype = CONSTR_DEFAULT;
882  cooked->conoid = InvalidOid; /* until created */
883  cooked->name = NULL;
884  cooked->attnum = attnum;
885  cooked->expr = colDef->cooked_default;
886  cooked->skip_validation = false;
887  cooked->is_local = true; /* not used for defaults */
888  cooked->inhcount = 0; /* ditto */
889  cooked->is_no_inherit = false;
890  cookedDefaults = lappend(cookedDefaults, cooked);
891  attr->atthasdef = true;
892  }
893 
894  if (colDef->identity)
895  attr->attidentity = colDef->identity;
896 
897  if (colDef->generated)
898  attr->attgenerated = colDef->generated;
899 
900  if (colDef->compression)
901  attr->attcompression = GetAttributeCompression(attr->atttypid,
902  colDef->compression);
903  }
904 
905  /*
906  * If the statement hasn't specified an access method, but we're defining
907  * a type of relation that needs one, use the default.
908  */
909  if (stmt->accessMethod != NULL)
910  {
911  accessMethod = stmt->accessMethod;
912 
913  if (partitioned)
914  ereport(ERROR,
915  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
916  errmsg("specifying a table access method is not supported on a partitioned table")));
917 
918  }
919  else if (relkind == RELKIND_RELATION ||
920  relkind == RELKIND_TOASTVALUE ||
921  relkind == RELKIND_MATVIEW)
922  accessMethod = default_table_access_method;
923 
924  /* look up the access method, verify it is for a table */
925  if (accessMethod != NULL)
926  accessMethodId = get_table_am_oid(accessMethod, false);
927 
928  /*
929  * Create the relation. Inherited defaults and constraints are passed in
930  * for immediate handling --- since they don't need parsing, they can be
931  * stored immediately.
932  */
933  relationId = heap_create_with_catalog(relname,
934  namespaceId,
935  tablespaceId,
936  InvalidOid,
937  InvalidOid,
938  ofTypeId,
939  ownerId,
940  accessMethodId,
941  descriptor,
942  list_concat(cookedDefaults,
943  old_constraints),
944  relkind,
945  stmt->relation->relpersistence,
946  false,
947  false,
948  stmt->oncommit,
949  reloptions,
950  true,
952  false,
953  InvalidOid,
954  typaddress);
955 
956  /*
957  * We must bump the command counter to make the newly-created relation
958  * tuple visible for opening.
959  */
961 
962  /*
963  * Open the new relation and acquire exclusive lock on it. This isn't
964  * really necessary for locking out other backends (since they can't see
965  * the new rel anyway until we commit), but it keeps the lock manager from
966  * complaining about deadlock risks.
967  */
968  rel = relation_open(relationId, AccessExclusiveLock);
969 
970  /*
971  * Now add any newly specified column default and generation expressions
972  * to the new relation. These are passed to us in the form of raw
973  * parsetrees; we need to transform them to executable expression trees
974  * before they can be added. The most convenient way to do that is to
975  * apply the parser's transformExpr routine, but transformExpr doesn't
976  * work unless we have a pre-existing relation. So, the transformation has
977  * to be postponed to this final step of CREATE TABLE.
978  *
979  * This needs to be before processing the partitioning clauses because
980  * those could refer to generated columns.
981  */
982  if (rawDefaults)
983  AddRelationNewConstraints(rel, rawDefaults, NIL,
984  true, true, false, queryString);
985 
986  /*
987  * Make column generation expressions visible for use by partitioning.
988  */
990 
991  /* Process and store partition bound, if any. */
992  if (stmt->partbound)
993  {
994  PartitionBoundSpec *bound;
995  ParseState *pstate;
996  Oid parentId = linitial_oid(inheritOids),
997  defaultPartOid;
998  Relation parent,
999  defaultRel = NULL;
1000  ParseNamespaceItem *nsitem;
1001 
1002  /* Already have strong enough lock on the parent */
1003  parent = table_open(parentId, NoLock);
1004 
1005  /*
1006  * We are going to try to validate the partition bound specification
1007  * against the partition key of parentRel, so it better have one.
1008  */
1009  if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1010  ereport(ERROR,
1011  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1012  errmsg("\"%s\" is not partitioned",
1013  RelationGetRelationName(parent))));
1014 
1015  /*
1016  * The partition constraint of the default partition depends on the
1017  * partition bounds of every other partition. It is possible that
1018  * another backend might be about to execute a query on the default
1019  * partition table, and that the query relies on previously cached
1020  * default partition constraints. We must therefore take a table lock
1021  * strong enough to prevent all queries on the default partition from
1022  * proceeding until we commit and send out a shared-cache-inval notice
1023  * that will make them update their index lists.
1024  *
1025  * Order of locking: The relation being added won't be visible to
1026  * other backends until it is committed, hence here in
1027  * DefineRelation() the order of locking the default partition and the
1028  * relation being added does not matter. But at all other places we
1029  * need to lock the default relation before we lock the relation being
1030  * added or removed i.e. we should take the lock in same order at all
1031  * the places such that lock parent, lock default partition and then
1032  * lock the partition so as to avoid a deadlock.
1033  */
1034  defaultPartOid =
1036  true));
1037  if (OidIsValid(defaultPartOid))
1038  defaultRel = table_open(defaultPartOid, AccessExclusiveLock);
1039 
1040  /* Transform the bound values */
1041  pstate = make_parsestate(NULL);
1042  pstate->p_sourcetext = queryString;
1043 
1044  /*
1045  * Add an nsitem containing this relation, so that transformExpr
1046  * called on partition bound expressions is able to report errors
1047  * using a proper context.
1048  */
1049  nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
1050  NULL, false, false);
1051  addNSItemToQuery(pstate, nsitem, false, true, true);
1052 
1053  bound = transformPartitionBound(pstate, parent, stmt->partbound);
1054 
1055  /*
1056  * Check first that the new partition's bound is valid and does not
1057  * overlap with any of existing partitions of the parent.
1058  */
1059  check_new_partition_bound(relname, parent, bound, pstate);
1060 
1061  /*
1062  * If the default partition exists, its partition constraints will
1063  * change after the addition of this new partition such that it won't
1064  * allow any row that qualifies for this new partition. So, check that
1065  * the existing data in the default partition satisfies the constraint
1066  * as it will exist after adding this partition.
1067  */
1068  if (OidIsValid(defaultPartOid))
1069  {
1070  check_default_partition_contents(parent, defaultRel, bound);
1071  /* Keep the lock until commit. */
1072  table_close(defaultRel, NoLock);
1073  }
1074 
1075  /* Update the pg_class entry. */
1076  StorePartitionBound(rel, parent, bound);
1077 
1078  table_close(parent, NoLock);
1079  }
1080 
1081  /* Store inheritance information for new rel. */
1082  StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
1083 
1084  /*
1085  * Process the partitioning specification (if any) and store the partition
1086  * key information into the catalog.
1087  */
1088  if (partitioned)
1089  {
1090  ParseState *pstate;
1091  char strategy;
1092  int partnatts;
1093  AttrNumber partattrs[PARTITION_MAX_KEYS];
1094  Oid partopclass[PARTITION_MAX_KEYS];
1095  Oid partcollation[PARTITION_MAX_KEYS];
1096  List *partexprs = NIL;
1097 
1098  pstate = make_parsestate(NULL);
1099  pstate->p_sourcetext = queryString;
1100 
1101  partnatts = list_length(stmt->partspec->partParams);
1102 
1103  /* Protect fixed-size arrays here and in executor */
1104  if (partnatts > PARTITION_MAX_KEYS)
1105  ereport(ERROR,
1106  (errcode(ERRCODE_TOO_MANY_COLUMNS),
1107  errmsg("cannot partition using more than %d columns",
1108  PARTITION_MAX_KEYS)));
1109 
1110  /*
1111  * We need to transform the raw parsetrees corresponding to partition
1112  * expressions into executable expression trees. Like column defaults
1113  * and CHECK constraints, we could not have done the transformation
1114  * earlier.
1115  */
1116  stmt->partspec = transformPartitionSpec(rel, stmt->partspec,
1117  &strategy);
1118 
1119  ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
1120  partattrs, &partexprs, partopclass,
1121  partcollation, strategy);
1122 
1123  StorePartitionKey(rel, strategy, partnatts, partattrs, partexprs,
1124  partopclass, partcollation);
1125 
1126  /* make it all visible */
1128  }
1129 
1130  /*
1131  * If we're creating a partition, create now all the indexes, triggers,
1132  * FKs defined in the parent.
1133  *
1134  * We can't do it earlier, because DefineIndex wants to know the partition
1135  * key which we just stored.
1136  */
1137  if (stmt->partbound)
1138  {
1139  Oid parentId = linitial_oid(inheritOids);
1140  Relation parent;
1141  List *idxlist;
1142  ListCell *cell;
1143 
1144  /* Already have strong enough lock on the parent */
1145  parent = table_open(parentId, NoLock);
1146  idxlist = RelationGetIndexList(parent);
1147 
1148  /*
1149  * For each index in the parent table, create one in the partition
1150  */
1151  foreach(cell, idxlist)
1152  {
1153  Relation idxRel = index_open(lfirst_oid(cell), AccessShareLock);
1154  AttrMap *attmap;
1155  IndexStmt *idxstmt;
1156  Oid constraintOid;
1157 
1158  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1159  {
1160  if (idxRel->rd_index->indisunique)
1161  ereport(ERROR,
1162  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1163  errmsg("cannot create foreign partition of partitioned table \"%s\"",
1164  RelationGetRelationName(parent)),
1165  errdetail("Table \"%s\" contains indexes that are unique.",
1166  RelationGetRelationName(parent))));
1167  else
1168  {
1169  index_close(idxRel, AccessShareLock);
1170  continue;
1171  }
1172  }
1173 
1175  RelationGetDescr(parent));
1176  idxstmt =
1177  generateClonedIndexStmt(NULL, idxRel,
1178  attmap, &constraintOid);
1180  idxstmt,
1181  InvalidOid,
1182  RelationGetRelid(idxRel),
1183  constraintOid,
1184  false, false, false, false, false);
1185 
1186  index_close(idxRel, AccessShareLock);
1187  }
1188 
1189  list_free(idxlist);
1190 
1191  /*
1192  * If there are any row-level triggers, clone them to the new
1193  * partition.
1194  */
1195  if (parent->trigdesc != NULL)
1196  CloneRowTriggersToPartition(parent, rel);
1197 
1198  /*
1199  * And foreign keys too. Note that because we're freshly creating the
1200  * table, there is no need to verify these new constraints.
1201  */
1202  CloneForeignKeyConstraints(NULL, parent, rel);
1203 
1204  table_close(parent, NoLock);
1205  }
1206 
1207  /*
1208  * Now add any newly specified CHECK constraints to the new relation. Same
1209  * as for defaults above, but these need to come after partitioning is set
1210  * up.
1211  */
1212  if (stmt->constraints)
1214  true, true, false, queryString);
1215 
1216  ObjectAddressSet(address, RelationRelationId, relationId);
1217 
1218  /*
1219  * Clean up. We keep lock on new relation (although it shouldn't be
1220  * visible to anyone else anyway, until commit).
1221  */
1222  relation_close(rel, NoLock);
1223 
1224  return address;
1225 }
RangeVar * relation
Definition: parsenodes.h:2183
bytea * heap_reloptions(char relkind, Datum reloptions, bool validate)
Definition: reloptions.c:2013
#define NIL
Definition: pg_list.h:65
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2581
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1427
OnCommitAction oncommit
Definition: parsenodes.h:2192
static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, char strategy)
Definition: tablecmds.c:16748
List * inhRelations
Definition: parsenodes.h:2185
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4768
ObjectAddress DefineIndex(Oid relationId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition: indexcmds.c:506
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
bool is_no_inherit
Definition: heap.h:45
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, char *validnsps[], bool acceptOidsOff, bool isReset)
Definition: reloptions.c:1149
void StorePartitionKey(Relation rel, char strategy, int16 partnatts, AttrNumber *partattrs, List *partexprs, Oid *partopclass, Oid *partcollation)
Definition: heap.c:3636
AttrNumber attnum
Definition: heap.h:29
List * partParams
Definition: parsenodes.h:821
#define RelationGetDescr(relation)
Definition: rel.h:503
int LOCKMODE
Definition: lockdefs.h:26
Oid GetUserId(void)
Definition: miscinit.c:495
char identity
Definition: parsenodes.h:680
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:79
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define AccessShareLock
Definition: lockdefs.h:36
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
List * list_concat(List *list1, const List *list2)
Definition: list.c:530
int errcode(int sqlerrcode)
Definition: elog.c:698
#define PARTITION_MAX_KEYS
static char GetAttributeCompression(Oid atttypid, char *compression)
Definition: tablecmds.c:18731
char generated
Definition: parsenodes.h:683
Form_pg_class rd_rel
Definition: rel.h:109
NameData relname
Definition: pg_class.h:38
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
#define OidIsValid(objectId)
Definition: c.h:710
static void StoreCatalogInheritance(Oid relationId, List *supers, bool child_is_partition)
Definition: tablecmds.c:3066
static PartitionSpec * transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
Definition: tablecmds.c:16677
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3621
Oid MyDatabaseTableSpace
Definition: globals.c:90
Definition: attmap.h:34
Oid get_rel_tablespace(Oid relid)
Definition: lsyscache.c:2025
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
bytea * view_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:1994
List * constraints
Definition: parsenodes.h:2190
PartitionBoundSpec * transformPartitionBound(ParseState *pstate, Relation parent, PartitionBoundSpec *spec)
#define NAMEDATALEN
char * accessMethod
Definition: parsenodes.h:2194
PartitionBoundSpec * partbound
Definition: parsenodes.h:2187
Node * cooked_default
Definition: parsenodes.h:679
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3308
Form_pg_index rd_index
Definition: rel.h:187
void check_new_partition_bound(char *relname, Relation parent, PartitionBoundSpec *spec, ParseState *pstate)
Definition: partbounds.c:2908
AttrNumber attnum
Definition: heap.h:40
#define ERROR
Definition: elog.h:46
#define ACL_CREATE
Definition: parsenodes.h:92
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
TriggerDesc * trigdesc
Definition: rel.h:115
void check_default_partition_contents(Relation parent, Relation default_rel, PartitionBoundSpec *new_spec)
Definition: partbounds.c:3267
bool missingMode
Definition: heap.h:31
int inhcount
Definition: heap.h:44
Oid GetDefaultTablespace(char relpersistence, bool partitioned)
Definition: tablespace.c:1144
#define NoLock
Definition: lockdefs.h:34
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:72
int errdetail(const char *fmt,...)
Definition: elog.c:1042
char generated
Definition: heap.h:32
#define RelationGetRelationName(relation)
Definition: rel.h:511
List * options
Definition: parsenodes.h:2191
Node * raw_default
Definition: heap.h:30
static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel, Relation partitionRel)
Definition: tablecmds.c:9757
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
#define ACL_USAGE
Definition: parsenodes.h:90
bool skip_validation
Definition: heap.h:42
#define HEAP_RELOPT_NAMESPACES
Definition: reloptions.h:61
const char * p_sourcetext
Definition: parse_node.h:181
ConstrType contype
Definition: heap.h:37
Node * raw_default
Definition: parsenodes.h:678
List * lappend(List *list, void *datum)
Definition: list.c:336
char * tablespacename
Definition: parsenodes.h:2193
bytea * partitioned_table_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:1979
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:535
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:411
void CommandCounterIncrement(void)
Definition: xact.c:1021
static List * MergeAttributes(List *schema, List *supers, char relpersistence, bool is_partition, List **supconstr)
Definition: tablecmds.c:2266
bool allowSystemTableMods
Definition: globals.c:123
#define InvalidOid
Definition: postgres_ext.h:36
void StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound)
Definition: heap.c:3794
int16 attnum
Definition: pg_attribute.h:83
#define ereport(elevel,...)
Definition: elog.h:157
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:174
List * tableElts
Definition: parsenodes.h:2184
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:689
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid reltypeid, Oid reloftypeid, Oid ownerid, Oid accessmtd, TupleDesc tupdesc, List *cooked_constraints, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, OnCommitAction oncommit, Datum reloptions, bool use_user_acl, bool allow_system_table_mods, bool is_internal, Oid relrewrite, ObjectAddress *typaddress)
Definition: heap.c:1143
Oid get_table_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:173
bool InSecurityRestrictedOperation(void)
Definition: miscinit.c:627
IndexStmt * generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, const AttrMap *attmap, Oid *constraintOid)
#define linitial_oid(l)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:149
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4573
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
char relpersistence
Definition: primnodes.h:71
#define AccessExclusiveLock
Definition: lockdefs.h:45
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1473
void list_free(List *list)
Definition: list.c:1391
static void CloneRowTriggersToPartition(Relation parent, Relation partition)
Definition: tablecmds.c:17651
#define elog(elevel,...)
Definition: elog.h:232
Oid conoid
Definition: heap.h:38
Node * expr
Definition: heap.h:41
char * default_table_access_method
Definition: tableam.c:48
TupleDesc BuildDescForRelation(List *schema)
Definition: tupdesc.c:777
char * compression
Definition: parsenodes.h:672
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4806
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
PartitionSpec * partspec
Definition: parsenodes.h:2188
Definition: pg_list.h:50
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1899
int16 AttrNumber
Definition: attnum.h:21
char * name
Definition: heap.h:39
#define RelationGetRelid(relation)
Definition: rel.h:477
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
TypeName * ofTypename
Definition: parsenodes.h:2189
#define lfirst_oid(lc)
Definition: pg_list.h:171
bool is_local
Definition: heap.h:43
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition: partdesc.c:455

◆ ExecuteTruncate()

void ExecuteTruncate ( TruncateStmt stmt)

Definition at line 1611 of file tablecmds.c.

References AccessExclusiveLock, TruncateStmt::behavior, ereport, errcode(), errhint(), errmsg(), ERROR, ExecuteTruncateGuts(), find_all_inheritors(), RangeVar::inh, lappend(), lappend_oid(), lfirst, lfirst_oid, list_member_oid(), NIL, NoLock, RangeVarCallbackForTruncate(), RangeVarGetRelidExtended(), RelationData::rd_rel, RELATION_IS_OTHER_TEMP, RelationGetRelid, RelationIsLogicallyLogged, TruncateStmt::relations, TruncateStmt::restart_seqs, table_close(), table_open(), truncate_check_activity(), and truncate_check_rel().

Referenced by standard_ProcessUtility().

1612 {
1613  List *rels = NIL;
1614  List *relids = NIL;
1615  List *relids_logged = NIL;
1616  ListCell *cell;
1617 
1618  /*
1619  * Open, exclusive-lock, and check all the explicitly-specified relations
1620  */
1621  foreach(cell, stmt->relations)
1622  {
1623  RangeVar *rv = lfirst(cell);
1624  Relation rel;
1625  bool recurse = rv->inh;
1626  Oid myrelid;
1627  LOCKMODE lockmode = AccessExclusiveLock;
1628 
1629  myrelid = RangeVarGetRelidExtended(rv, lockmode,
1631  NULL);
1632 
1633  /* don't throw error for "TRUNCATE foo, foo" */
1634  if (list_member_oid(relids, myrelid))
1635  continue;
1636 
1637  /* open the relation, we already hold a lock on it */
1638  rel = table_open(myrelid, NoLock);
1639 
1640  /*
1641  * RangeVarGetRelidExtended() has done most checks with its callback,
1642  * but other checks with the now-opened Relation remain.
1643  */
1645 
1646  rels = lappend(rels, rel);
1647  relids = lappend_oid(relids, myrelid);
1648 
1649  /* Log this relation only if needed for logical decoding */
1650  if (RelationIsLogicallyLogged(rel))
1651  relids_logged = lappend_oid(relids_logged, myrelid);
1652 
1653  if (recurse)
1654  {
1655  ListCell *child;
1656  List *children;
1657 
1658  children = find_all_inheritors(myrelid, lockmode, NULL);
1659 
1660  foreach(child, children)
1661  {
1662  Oid childrelid = lfirst_oid(child);
1663 
1664  if (list_member_oid(relids, childrelid))
1665  continue;
1666 
1667  /* find_all_inheritors already got lock */
1668  rel = table_open(childrelid, NoLock);
1669 
1670  /*
1671  * It is possible that the parent table has children that are
1672  * temp tables of other backends. We cannot safely access
1673  * such tables (because of buffering issues), and the best
1674  * thing to do is to silently ignore them. Note that this
1675  * check is the same as one of the checks done in
1676  * truncate_check_activity() called below, still it is kept
1677  * here for simplicity.
1678  */
1679  if (RELATION_IS_OTHER_TEMP(rel))
1680  {
1681  table_close(rel, lockmode);
1682  continue;
1683  }
1684 
1685  /*
1686  * Inherited TRUNCATE commands perform access permission
1687  * checks on the parent table only. So we skip checking the
1688  * children's permissions and don't call
1689  * truncate_check_perms() here.
1690  */
1693 
1694  rels = lappend(rels, rel);
1695  relids = lappend_oid(relids, childrelid);
1696 
1697  /* Log this relation only if needed for logical decoding */
1698  if (RelationIsLogicallyLogged(rel))
1699  relids_logged = lappend_oid(relids_logged, childrelid);
1700  }
1701  }
1702  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1703  ereport(ERROR,
1704  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1705  errmsg("cannot truncate only a partitioned table"),
1706  errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1707  }
1708 
1709  ExecuteTruncateGuts(rels, relids, relids_logged,
1710  stmt->behavior, stmt->restart_seqs);
1711 
1712  /* And close the rels */
1713  foreach(cell, rels)
1714  {
1715  Relation rel = (Relation) lfirst(cell);
1716 
1717  table_close(rel, NoLock);
1718  }
1719 }
#define NIL
Definition: pg_list.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int errhint(const char *fmt,...)
Definition: elog.c:1156
int LOCKMODE
Definition: lockdefs.h:26
static void RangeVarCallbackForTruncate(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:16484
int errcode(int sqlerrcode)
Definition: elog.c:698
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:674
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
DropBehavior behavior
Definition: parsenodes.h:2782
struct RelationData * Relation
Definition: relcache.h:26
#define ERROR
Definition: elog.h:46
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs)
Definition: tablecmds.c:1735
List * relations
Definition: parsenodes.h:2780
#define NoLock
Definition: lockdefs.h:34
bool restart_seqs
Definition: parsenodes.h:2781
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:237
bool inh
Definition: primnodes.h:69
List * lappend(List *list, void *datum)
Definition: list.c:336
#define ereport(elevel,...)
Definition: elog.h:157
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2168
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:689
#define lfirst(lc)
Definition: pg_list.h:169
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:631
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2110
#define AccessExclusiveLock
Definition: lockdefs.h:45
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:256
int errmsg(const char *fmt,...)
Definition: elog.c:909
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:477
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ ExecuteTruncateGuts()

void ExecuteTruncateGuts ( List explicit_rels,
List relids,
List relids_logged,
DropBehavior  behavior,
bool  restart_seqs 
)

Definition at line 1735 of file tablecmds.c.

References AccessExclusiveLock, aclcheck_error(), ACLCHECK_NOT_OWNER, AfterTriggerBeginQuery(), AfterTriggerEndQuery(), Assert, CheckTableForSerializableConflictIn(), CreateExecutorState(), CurrentMemoryContext, xl_heap_truncate::dbId, DROP_CASCADE, DROP_RESTRICT, HASHCTL::entrysize, ereport, errmsg(), EState::es_opened_result_relations, ExecASTruncateTriggers(), ExecBSTruncateTriggers(), FdwRoutine::ExecForeignTruncate, xl_heap_truncate::flags, FreeExecutorState(), GetCurrentSubTransactionId(), GetFdwRoutineByServerId(), GetForeignServerIdByRelId(), getOwnedSequences(), GetUserId(), HASH_BLOBS, HASH_CONTEXT, hash_create(), hash_destroy(), HASH_ELEM, HASH_ENTER, hash_search(), hash_seq_init(), hash_seq_search(), HASHCTL::hcxt, heap_truncate_check_FKs(), heap_truncate_find_FKs(), heap_truncate_one_rel(), i, InitResultRelInfo(), HASHCTL::keysize, lappend(), lappend_oid(), lfirst, lfirst_oid, list_copy(), list_difference_ptr(), list_length(), MyDatabaseId, NIL, NoLock, NOTICE, xl_heap_truncate::nrelids, OBJECT_SEQUENCE, OidIsValid, palloc(), pg_class_ownercheck(), PG_END_TRY, PG_FINALLY, PG_TRY, pgstat_count_truncate(), RelationData::rd_createSubid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_rel, REINDEX_REL_PROCESS_TOAST, reindex_relation(), relation_close(), relation_open(), RelationGetRelationName, RelationGetRelid, RelationIsLogicallyLogged, RelationSetNewRelfilenode(), OnCommitItem::relid, ForeignTruncateInfo::rels, ResetSequence(), ForeignTruncateInfo::serverid, SizeOfHeapTruncate, table_close(), table_open(), truncate_check_activity(), truncate_check_perms(), truncate_check_rel(), XLH_TRUNCATE_CASCADE, XLH_TRUNCATE_RESTART_SEQS, XLOG_HEAP_TRUNCATE, XLOG_INCLUDE_ORIGIN, XLogBeginInsert(), XLogInsert(), XLogLogicalInfoActive, XLogRegisterData(), and XLogSetRecordFlags().

Referenced by apply_handle_truncate(), and ExecuteTruncate().

1739 {
1740  List *rels;
1741  List *seq_relids = NIL;
1742  HTAB *ft_htab = NULL;
1743  EState *estate;
1744  ResultRelInfo *resultRelInfos;
1745  ResultRelInfo *resultRelInfo;
1746  SubTransactionId mySubid;
1747  ListCell *cell;
1748  Oid *logrelids;
1749 
1750  /*
1751  * Check the explicitly-specified relations.
1752  *
1753  * In CASCADE mode, suck in all referencing relations as well. This
1754  * requires multiple iterations to find indirectly-dependent relations. At
1755  * each phase, we need to exclusive-lock new rels before looking for their
1756  * dependencies, else we might miss something. Also, we check each rel as
1757  * soon as we open it, to avoid a faux pas such as holding lock for a long
1758  * time on a rel we have no permissions for.
1759  */
1760  rels = list_copy(explicit_rels);
1761  if (behavior == DROP_CASCADE)
1762  {
1763  for (;;)
1764  {
1765  List *newrelids;
1766 
1767  newrelids = heap_truncate_find_FKs(relids);
1768  if (newrelids == NIL)
1769  break; /* nothing else to add */
1770 
1771  foreach(cell, newrelids)
1772  {
1773  Oid relid = lfirst_oid(cell);
1774  Relation rel;
1775 
1776  rel = table_open(relid, AccessExclusiveLock);
1777  ereport(NOTICE,
1778  (errmsg("truncate cascades to table \"%s\"",
1779  RelationGetRelationName(rel))));
1780  truncate_check_rel(relid, rel->rd_rel);
1781  truncate_check_perms(relid, rel->rd_rel);
1783  rels = lappend(rels, rel);
1784  relids = lappend_oid(relids, relid);
1785 
1786  /* Log this relation only if needed for logical decoding */
1787  if (RelationIsLogicallyLogged(rel))
1788  relids_logged = lappend_oid(relids_logged, relid);
1789  }
1790  }
1791  }
1792 
1793  /*
1794  * Check foreign key references. In CASCADE mode, this should be
1795  * unnecessary since we just pulled in all the references; but as a
1796  * cross-check, do it anyway if in an Assert-enabled build.
1797  */
1798 #ifdef USE_ASSERT_CHECKING
1799  heap_truncate_check_FKs(rels, false);
1800 #else
1801  if (behavior == DROP_RESTRICT)
1802  heap_truncate_check_FKs(rels, false);
1803 #endif
1804 
1805  /*
1806  * If we are asked to restart sequences, find all the sequences, lock them
1807  * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1808  * We want to do this early since it's pointless to do all the truncation
1809  * work only to fail on sequence permissions.
1810  */
1811  if (restart_seqs)
1812  {
1813  foreach(cell, rels)
1814  {
1815  Relation rel = (Relation) lfirst(cell);
1816  List *seqlist = getOwnedSequences(RelationGetRelid(rel));
1817  ListCell *seqcell;
1818 
1819  foreach(seqcell, seqlist)
1820  {
1821  Oid seq_relid = lfirst_oid(seqcell);
1822  Relation seq_rel;
1823 
1824  seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1825 
1826  /* This check must match AlterSequence! */
1827  if (!pg_class_ownercheck(seq_relid, GetUserId()))
1829  RelationGetRelationName(seq_rel));
1830 
1831  seq_relids = lappend_oid(seq_relids, seq_relid);
1832 
1833  relation_close(seq_rel, NoLock);
1834  }
1835  }
1836  }
1837 
1838  /* Prepare to catch AFTER triggers. */
1840 
1841  /*
1842  * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1843  * each relation. We don't need to call ExecOpenIndices, though.
1844  *
1845  * We put the ResultRelInfos in the es_opened_result_relations list, even
1846  * though we don't have a range table and don't populate the
1847  * es_result_relations array. That's a bit bogus, but it's enough to make
1848  * ExecGetTriggerResultRel() find them.
1849  */
1850  estate = CreateExecutorState();
1851  resultRelInfos = (ResultRelInfo *)
1852  palloc(list_length(rels) * sizeof(ResultRelInfo));
1853  resultRelInfo = resultRelInfos;
1854  foreach(cell, rels)
1855  {
1856  Relation rel = (Relation) lfirst(cell);
1857 
1858  InitResultRelInfo(resultRelInfo,
1859  rel,
1860  0, /* dummy rangetable index */
1861  NULL,
1862  0);
1863  estate->es_opened_result_relations =
1864  lappend(estate->es_opened_result_relations, resultRelInfo);
1865  resultRelInfo++;
1866  }
1867 
1868  /*
1869  * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
1870  * truncating (this is because one of them might throw an error). Also, if
1871  * we were to allow them to prevent statement execution, that would need
1872  * to be handled here.
1873  */
1874  resultRelInfo = resultRelInfos;
1875  foreach(cell, rels)
1876  {
1877  ExecBSTruncateTriggers(estate, resultRelInfo);
1878  resultRelInfo++;
1879  }
1880 
1881  /*
1882  * OK, truncate each table.
1883  */
1884  mySubid = GetCurrentSubTransactionId();
1885 
1886  foreach(cell, rels)
1887  {
1888  Relation rel = (Relation) lfirst(cell);
1889 
1890  /* Skip partitioned tables as there is nothing to do */
1891  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1892  continue;
1893 
1894  /*
1895  * Build the lists of foreign tables belonging to each foreign server
1896  * and pass each list to the foreign data wrapper's callback function,
1897  * so that each server can truncate its all foreign tables in bulk.
1898  * Each list is saved as a single entry in a hash table that uses the
1899  * server OID as lookup key.
1900  */
1901  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1902  {
1904  bool found;
1905  ForeignTruncateInfo *ft_info;
1906 
1907  /* First time through, initialize hashtable for foreign tables */
1908  if (!ft_htab)
1909  {
1910  HASHCTL hctl;
1911 
1912  memset(&hctl, 0, sizeof(HASHCTL));
1913  hctl.keysize = sizeof(Oid);
1914  hctl.entrysize = sizeof(ForeignTruncateInfo);
1915  hctl.hcxt = CurrentMemoryContext;
1916 
1917  ft_htab = hash_create("TRUNCATE for Foreign Tables",
1918  32, /* start small and extend */
1919  &hctl,
1921  }
1922 
1923  /* Find or create cached entry for the foreign table */
1924  ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
1925  if (!found)
1926  {
1927  ft_info->serverid = serverid;
1928  ft_info->rels = NIL;
1929  }
1930 
1931  /*
1932  * Save the foreign table in the entry of the server that the
1933  * foreign table belongs to.
1934  */
1935  ft_info->rels = lappend(ft_info->rels, rel);
1936  continue;
1937  }
1938 
1939  /*
1940  * Normally, we need a transaction-safe truncation here. However, if
1941  * the table was either created in the current (sub)transaction or has
1942  * a new relfilenode in the current (sub)transaction, then we can just
1943  * truncate it in-place, because a rollback would cause the whole
1944  * table or the current physical file to be thrown away anyway.
1945  */
1946  if (rel->rd_createSubid == mySubid ||
1947  rel->rd_newRelfilenodeSubid == mySubid)
1948  {
1949  /* Immediate, non-rollbackable truncation is OK */
1950  heap_truncate_one_rel(rel);
1951  }
1952  else
1953  {
1954  Oid heap_relid;
1955  Oid toast_relid;
1956  ReindexParams reindex_params = {0};
1957 
1958  /*
1959  * This effectively deletes all rows in the table, and may be done
1960  * in a serializable transaction. In that case we must record a
1961  * rw-conflict in to this transaction from each transaction
1962  * holding a predicate lock on the table.
1963  */
1965 
1966  /*
1967  * Need the full transaction-safe pushups.
1968  *
1969  * Create a new empty storage file for the relation, and assign it
1970  * as the relfilenode value. The old storage file is scheduled for
1971  * deletion at commit.
1972  */
1973  RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence);
1974 
1975  heap_relid = RelationGetRelid(rel);
1976 
1977  /*
1978  * The same for the toast table, if any.
1979  */
1980  toast_relid = rel->rd_rel->reltoastrelid;
1981  if (OidIsValid(toast_relid))
1982  {
1983  Relation toastrel = relation_open(toast_relid,
1985 
1986  RelationSetNewRelfilenode(toastrel,
1987  toastrel->rd_rel->relpersistence);
1988  table_close(toastrel, NoLock);
1989  }
1990 
1991  /*
1992  * Reconstruct the indexes to match, and we're done.
1993  */
1995  &reindex_params);
1996  }
1997 
1998  pgstat_count_truncate(rel);
1999  }
2000 
2001  /* Now go through the hash table, and truncate foreign tables */
2002  if (ft_htab)
2003  {
2004  ForeignTruncateInfo *ft_info;
2005  HASH_SEQ_STATUS seq;
2006 
2007  hash_seq_init(&seq, ft_htab);
2008 
2009  PG_TRY();
2010  {
2011  while ((ft_info = hash_seq_search(&seq)) != NULL)
2012  {
2013  FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2014 
2015  /* truncate_check_rel() has checked that already */
2016  Assert(routine->ExecForeignTruncate != NULL);
2017 
2018  routine->ExecForeignTruncate(ft_info->rels,
2019  behavior,
2020  restart_seqs);
2021  }
2022  }
2023  PG_FINALLY();
2024  {
2025  hash_destroy(ft_htab);
2026  }
2027  PG_END_TRY();
2028  }
2029 
2030  /*
2031  * Restart owned sequences if we were asked to.
2032  */
2033  foreach(cell, seq_relids)
2034  {
2035  Oid seq_relid = lfirst_oid(cell);
2036 
2037  ResetSequence(seq_relid);
2038  }
2039 
2040  /*
2041  * Write a WAL record to allow this set of actions to be logically
2042  * decoded.
2043  *
2044  * Assemble an array of relids so we can write a single WAL record for the
2045  * whole action.
2046  */
2047  if (list_length(relids_logged) > 0)
2048  {
2049  xl_heap_truncate xlrec;
2050  int i = 0;
2051 
2052  /* should only get here if wal_level >= logical */
2054 
2055  logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
2056  foreach(cell, relids_logged)
2057  logrelids[i++] = lfirst_oid(cell);
2058 
2059  xlrec.dbId = MyDatabaseId;
2060  xlrec.nrelids = list_length(relids_logged);
2061  xlrec.flags = 0;
2062  if (behavior == DROP_CASCADE)
2063  xlrec.flags |= XLH_TRUNCATE_CASCADE;
2064  if (restart_seqs)
2066 
2067  XLogBeginInsert();
2068  XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
2069  XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
2070 
2072 
2073  (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
2074  }
2075 
2076  /*
2077  * Process all AFTER STATEMENT TRUNCATE triggers.
2078  */
2079  resultRelInfo = resultRelInfos;
2080  foreach(cell, rels)
2081  {
2082  ExecASTruncateTriggers(estate, resultRelInfo);
2083  resultRelInfo++;
2084  }
2085 
2086  /* Handle queued AFTER triggers */
2087  AfterTriggerEndQuery(estate);
2088 
2089  /* We can clean up the EState now */
2090  FreeExecutorState(estate);
2091 
2092  /*
2093  * Close any rels opened by CASCADE (can't do this while EState still
2094  * holds refs)
2095  */
2096  rels = list_difference_ptr(rels, explicit_rels);
2097  foreach(cell, rels)
2098  {
2099  Relation rel = (Relation) lfirst(cell);
2100 
2101  table_close(rel, NoLock);
2102  }
2103 }
#define NIL
Definition: pg_list.h:65
#define XLH_TRUNCATE_CASCADE
Definition: heapam_xlog.h:120
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:862
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
MemoryContext hcxt
Definition: hsearch.h:86
Oid GetUserId(void)
Definition: miscinit.c:495
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3369
List * list_difference_ptr(const List *list1, const List *list2)
Definition: list.c:1117
Size entrysize
Definition: hsearch.h:76
FdwRoutine * GetFdwRoutineByServerId(Oid serverid)
Definition: foreign.c:362
List * list_copy(const List *oldlist)
Definition: list.c:1418
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3413
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:103
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:213
uint32 SubTransactionId
Definition: c.h:591
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:674
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
static void truncate_check_perms(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2150
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
#define OidIsValid(objectId)
Definition: c.h:710
void RelationSetNewRelfilenode(Relation relation, char persistence)
Definition: relcache.c:3598
void FreeExecutorState(EState *estate)
Definition: execUtils.c:186
Definition: dynahash.c:219
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3308
struct RelationData * Relation
Definition: relcache.h:26
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3084
#define XLogLogicalInfoActive()
Definition: xlog.h:183
struct ResultRelInfo ResultRelInfo
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
List * es_opened_result_relations
Definition: execnodes.h:578
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3131
#define RelationGetRelationName(relation)
Definition: rel.h:511
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
void pgstat_count_truncate(Relation rel)
Definition: pgstat.c:2344
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:416
EState * CreateExecutorState(void)
Definition: execUtils.c:90
List * lappend(List *list, void *datum)
Definition: list.c:336
ExecForeignTruncate_function ExecForeignTruncate
Definition: fdwapi.h:263
SubTransactionId rd_createSubid
Definition: rel.h:102
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:340
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:434
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:878
#define HASH_BLOBS
Definition: hsearch.h:97
#define PG_FINALLY()
Definition: elog.h:330
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition: execMain.c:1193
Oid MyDatabaseId
Definition: globals.c:88
Size keysize
Definition: hsearch.h:75
#define XLH_TRUNCATE_RESTART_SEQS
Definition: heapam_xlog.h:121
#define XLOG_HEAP_TRUNCATE
Definition: heapam_xlog.h:35
#define ereport(elevel,...)
Definition: elog.h:157
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2168
#define NOTICE
Definition: elog.h:37
void AfterTriggerBeginQuery(void)
Definition: trigger.c:4670
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4818
#define SizeOfHeapTruncate
Definition: heapam_xlog.h:136
Oid GetForeignServerIdByRelId(Oid relid)
Definition: foreign.c:340
static int list_length(const List *l)
Definition: pg_list.h:149
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4529
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2110
struct ForeignTruncateInfo ForeignTruncateInfo
bool reindex_relation(Oid relid, int flags, ReindexParams *params)
Definition: index.c:3795
#define AccessExclusiveLock
Definition: lockdefs.h:45
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:4690
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
int i
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:155
void ResetSequence(Oid seq_relid)
Definition: sequence.c:270
#define PG_TRY()
Definition: elog.h:313
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
void XLogBeginInsert(void)
Definition: xloginsert.c:135
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:477
#define PG_END_TRY()
Definition: elog.h:338
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3508
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ find_composite_type_dependencies()

void find_composite_type_dependencies ( Oid  typeOid,
Relation  origRelation,
const char *  origTypeName 
)

Definition at line 6309 of file tablecmds.c.

References AccessShareLock, BTEqualStrategyNumber, check_stack_depth(), ereport, errcode(), errmsg(), ERROR, find_composite_type_dependencies(), GETSTRUCT, HeapTupleIsValid, sort-test::key, NameStr, ObjectIdGetDatum, OidIsValid, RelationData::rd_att, RelationData::rd_rel, relation_close(), relation_open(), RelationGetRelationName, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_open(), and TupleDescAttr.

Referenced by ATPrepAlterColumnType(), ATRewriteTables(), find_composite_type_dependencies(), and get_rels_with_domain().

6311 {
6312  Relation depRel;
6313  ScanKeyData key[2];
6314  SysScanDesc depScan;
6315  HeapTuple depTup;
6316 
6317  /* since this function recurses, it could be driven to stack overflow */
6319 
6320  /*
6321  * We scan pg_depend to find those things that depend on the given type.
6322  * (We assume we can ignore refobjsubid for a type.)
6323  */
6324  depRel = table_open(DependRelationId, AccessShareLock);
6325 
6326  ScanKeyInit(&key[0],
6327  Anum_pg_depend_refclassid,
6328  BTEqualStrategyNumber, F_OIDEQ,
6329  ObjectIdGetDatum(TypeRelationId));
6330  ScanKeyInit(&key[1],
6331  Anum_pg_depend_refobjid,
6332  BTEqualStrategyNumber, F_OIDEQ,
6333  ObjectIdGetDatum(typeOid));
6334 
6335  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6336  NULL, 2, key);
6337 
6338  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6339  {
6340  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6341  Relation rel;
6342  Form_pg_attribute att;
6343 
6344  /* Check for directly dependent types */
6345  if (pg_depend->classid == TypeRelationId)
6346  {
6347  /*
6348  * This must be an array, domain, or range containing the given
6349  * type, so recursively check for uses of this type. Note that
6350  * any error message will mention the original type not the
6351  * container; this is intentional.
6352  */
6353  find_composite_type_dependencies(pg_depend->objid,
6354  origRelation, origTypeName);
6355  continue;
6356  }
6357 
6358  /* Else, ignore dependees that aren't user columns of relations */
6359  /* (we assume system columns are never of interesting types) */
6360  if (pg_depend->classid != RelationRelationId ||
6361  pg_depend->objsubid <= 0)
6362  continue;
6363 
6364  rel = relation_open(pg_depend->objid, AccessShareLock);
6365  att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
6366 
6367  if (rel->rd_rel->relkind == RELKIND_RELATION ||
6368  rel->rd_rel->relkind == RELKIND_MATVIEW ||
6369  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6370  {
6371  if (origTypeName)
6372  ereport(ERROR,
6373  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6374  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6375  origTypeName,
6377  NameStr(att->attname))));
6378  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6379  ereport(ERROR,
6380  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6381  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6382  RelationGetRelationName(origRelation),
6384  NameStr(att->attname))));
6385  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
6386  ereport(ERROR,
6387  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6388  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
6389  RelationGetRelationName(origRelation),
6391  NameStr(att->attname))));
6392  else
6393  ereport(ERROR,
6394  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6395  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
6396  RelationGetRelationName(origRelation),
6398  NameStr(att->attname))));
6399  }
6400  else if (OidIsValid(rel->rd_rel->reltype))
6401  {
6402  /*
6403  * A view or composite type itself isn't a problem, but we must
6404  * recursively check for indirect dependencies via its rowtype.
6405  */
6407  origRelation, origTypeName);
6408  }
6409 
6411  }
6412 
6413  systable_endscan(depScan);
6414 
6416 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:595
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:6309
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:698
Form_pg_class rd_rel
Definition: rel.h:109
#define OidIsValid(objectId)
Definition: c.h:710
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:383
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:502
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
void check_stack_depth(void)
Definition: postgres.c:3469
#define RelationGetRelationName(relation)
Definition: rel.h:511
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
TupleDesc rd_att
Definition: rel.h:110
#define ereport(elevel,...)
Definition: elog.h:157
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define NameStr(name)
Definition: c.h:681
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ PartConstraintImpliedByRelConstraint()

bool PartConstraintImpliedByRelConstraint ( Relation  scanrel,
List partConstraint 
)

Definition at line 17005 of file tablecmds.c.

References NullTest::arg, NullTest::argisrow, ConstraintImpliedByRelConstraint(), TupleConstr::has_not_null, i, IS_NOT_NULL, lappend(), NullTest::location, makeNode, makeVar(), TupleDescData::natts, NIL, NullTest::nulltesttype, RelationData::rd_att, RelationGetDescr, and TupleDescAttr.

Referenced by check_default_partition_contents(), DetachAddConstraintIfNeeded(), and QueuePartitionConstraintValidation().

17007 {
17008  List *existConstraint = NIL;
17009  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
17010  int i;
17011 
17012  if (constr && constr->has_not_null)
17013  {
17014  int natts = scanrel->rd_att->natts;
17015 
17016  for (i = 1; i <= natts; i++)
17017  {
17018  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
17019 
17020  if (att->attnotnull && !att->attisdropped)
17021  {
17022  NullTest *ntest = makeNode(NullTest);
17023 
17024  ntest->arg = (Expr *) makeVar(1,
17025  i,
17026  att->atttypid,
17027  att->atttypmod,
17028  att->attcollation,
17029  0);
17030  ntest->nulltesttype = IS_NOT_NULL;
17031 
17032  /*
17033  * argisrow=false is correct even for a composite column,
17034  * because attnotnull does not represent a SQL-spec IS NOT
17035  * NULL test in such a case, just IS DISTINCT FROM NULL.
17036  */
17037  ntest->argisrow = false;
17038  ntest->location = -1;
17039  existConstraint = lappend(existConstraint, ntest);
17040  }
17041  }
17042  }
17043 
17044  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
17045 }
#define NIL
Definition: pg_list.h:65
#define RelationGetDescr(relation)
Definition: rel.h:503
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
Expr * arg
Definition: primnodes.h:1265
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
List * lappend(List *list, void *datum)
Definition: list.c:336
TupleDesc rd_att
Definition: rel.h:110
NullTestType nulltesttype
Definition: primnodes.h:1266
#define makeNode(_type_)
Definition: nodes.h:584
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:17058
int location
Definition: primnodes.h:1268
int i
bool argisrow
Definition: primnodes.h:1267
bool has_not_null
Definition: tupdesc.h:44
Definition: pg_list.h:50

◆ PreCommit_on_commit_actions()

void PreCommit_on_commit_actions ( void  )

Definition at line 16285 of file tablecmds.c.

References add_exact_object_address(), Assert, ObjectAddress::classId, OnCommitItem::deleting_subid, DROP_CASCADE, heap_truncate(), InvalidSubTransactionId, lappend_oid(), lfirst, lfirst_oid, MyXactFlags, new_object_addresses(), NIL, object_address_present(), OnCommitItem::oncommit, ONCOMMIT_DELETE_ROWS, ONCOMMIT_DROP, ONCOMMIT_NOOP, ONCOMMIT_PRESERVE_ROWS, PERFORM_DELETION_INTERNAL, PERFORM_DELETION_QUIETLY, performMultipleDeletions(), OnCommitItem::relid, and XACT_FLAGS_ACCESSEDTEMPNAMESPACE.

Referenced by CommitTransaction(), and PrepareTransaction().

16286 {
16287  ListCell *l;
16288  List *oids_to_truncate = NIL;
16289  List *oids_to_drop = NIL;
16290 
16291  foreach(l, on_commits)
16292  {
16293  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
16294 
16295  /* Ignore entry if already dropped in this xact */
16297  continue;
16298 
16299  switch (oc->oncommit)
16300  {
16301  case ONCOMMIT_NOOP:
16303  /* Do nothing (there shouldn't be such entries, actually) */
16304  break;
16305  case ONCOMMIT_DELETE_ROWS:
16306 
16307  /*
16308  * If this transaction hasn't accessed any temporary
16309  * relations, we can skip truncating ON COMMIT DELETE ROWS
16310  * tables, as they must still be empty.
16311  */
16313  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
16314  break;
16315  case ONCOMMIT_DROP:
16316  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
16317  break;
16318  }
16319  }
16320 
16321  /*
16322  * Truncate relations before dropping so that all dependencies between
16323  * relations are removed after they are worked on. Doing it like this
16324  * might be a waste as it is possible that a relation being truncated will
16325  * be dropped anyway due to its parent being dropped, but this makes the
16326  * code more robust because of not having to re-check that the relation
16327  * exists at truncation time.
16328  */
16329  if (oids_to_truncate != NIL)
16330  heap_truncate(oids_to_truncate);
16331 
16332  if (oids_to_drop != NIL)
16333  {
16334  ObjectAddresses *targetObjects = new_object_addresses();
16335  ListCell *l;
16336 
16337  foreach(l, oids_to_drop)
16338  {
16339  ObjectAddress object;
16340 
16341  object.classId = RelationRelationId;
16342  object.objectId = lfirst_oid(l);
16343  object.objectSubId = 0;
16344 
16345  Assert(!object_address_present(&object, targetObjects));
16346 
16347  add_exact_object_address(&object, targetObjects);
16348  }
16349 
16350  /*
16351  * Since this is an automatic drop, rather than one directly initiated
16352  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
16353  */
16354  performMultipleDeletions(targetObjects, DROP_CASCADE,
16356 
16357 #ifdef USE_ASSERT_CHECKING
16358 
16359  /*
16360  * Note that table deletion will call remove_on_commit_action, so the
16361  * entry should get marked as deleted.
16362  */
16363  foreach(l, on_commits)
16364  {
16365  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
16366 
16367  if (oc->oncommit != ONCOMMIT_DROP)
16368  continue;
16369 
16371  }
16372 #endif
16373  }
16374 }
#define NIL
Definition: pg_list.h:65
OnCommitAction oncommit
Definition: tablecmds.c:110
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2545
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2485
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2430
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
static List * on_commits
Definition: tablecmds.c:123
int MyXactFlags
Definition: xact.c:132
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:102
SubTransactionId deleting_subid
Definition: tablecmds.c:120
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
#define PERFORM_DELETION_QUIETLY
Definition: dependency.h:135
void heap_truncate(List *relids)
Definition: heap.c:3328
#define InvalidSubTransactionId
Definition: c.h:593
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:372
Definition: pg_list.h:50
#define lfirst_oid(lc)
Definition: pg_list.h:171
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:133

◆ RangeVarCallbackOwnsRelation()

void RangeVarCallbackOwnsRelation ( const RangeVar relation,
Oid  relId,
Oid  oldRelId,
void *  arg 
)

Definition at line 16508 of file tablecmds.c.

References aclcheck_error(), ACLCHECK_NOT_OWNER, allowSystemTableMods, elog, ereport, errcode(), errmsg(), ERROR, get_rel_relkind(), get_relkind_objtype(), GETSTRUCT, GetUserId(), HeapTupleIsValid, IsSystemClass(), ObjectIdGetDatum, OidIsValid, pg_class_ownercheck(), ReleaseSysCache(), RangeVar::relname, RELOID, and SearchSysCache1().

Referenced by AlterSequence(), and ProcessUtilitySlow().

16510 {
16511  HeapTuple tuple;
16512 
16513  /* Nothing to do if the relation was not found. */
16514  if (!OidIsValid(relId))
16515  return;
16516 
16517  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
16518  if (!HeapTupleIsValid(tuple)) /* should not happen */
16519  elog(ERROR, "cache lookup failed for relation %u", relId);
16520 
16521  if (!pg_class_ownercheck(relId, GetUserId()))
16523  relation->relname);
16524 
16525  if (!allowSystemTableMods &&
16526  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
16527  ereport(ERROR,
16528  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
16529  errmsg("permission denied: \"%s\" is a system catalog",
16530  relation->relname)));
16531 
16532  ReleaseSysCache(tuple);
16533 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
Oid GetUserId(void)
Definition: miscinit.c:495
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1974
int errcode(int sqlerrcode)
Definition: elog.c:698
#define OidIsValid(objectId)
Definition: c.h:710
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:86
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3308
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
bool allowSystemTableMods
Definition: globals.c:123
#define ereport(elevel,...)
Definition: elog.h:157
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4818
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
ObjectType get_relkind_objtype(char relkind)

◆ RangeVarCallbackOwnsTable()

void RangeVarCallbackOwnsTable ( const RangeVar relation,
Oid  relId,
Oid  oldRelId,
void *  arg 
)

Definition at line 16452 of file tablecmds.c.

References aclcheck_error(), ACLCHECK_NOT_OWNER, ereport, errcode(), errmsg(), ERROR, get_rel_relkind(), get_relkind_objtype(), GetUserId(), OidIsValid, pg_class_ownercheck(), DropRelationCallbackState::relkind, and RangeVar::relname.

Referenced by cluster(), ExecRefreshMatView(), and ReindexTable().

16454 {
16455  char relkind;
16456 
16457  /* Nothing to do if the relation was not found. */
16458  if (!OidIsValid(relId))
16459  return;
16460 
16461  /*
16462  * If the relation does exist, check whether it's an index. But note that
16463  * the relation might have been dropped between the time we did the name
16464  * lookup and now. In that case, there's nothing to do.
16465  */
16466  relkind = get_rel_relkind(relId);
16467  if (!relkind)
16468  return;
16469  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
16470  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
16471  ereport(ERROR,
16472  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16473  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
16474 
16475  /* Check permissions */
16476  if (!pg_class_ownercheck(relId, GetUserId()))
16478 }
Oid GetUserId(void)
Definition: miscinit.c:495
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1974
int errcode(int sqlerrcode)
Definition: elog.c:698
#define OidIsValid(objectId)
Definition: c.h:710
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3308
#define ERROR
Definition: elog.h:46
#define ereport(elevel,...)
Definition: elog.h:157
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4818
int errmsg(const char *fmt,...)
Definition: elog.c:909
ObjectType get_relkind_objtype(char relkind)

◆ register_on_commit_action()

void register_on_commit_action ( Oid  relid,
OnCommitAction  action 
)

Definition at line 16226 of file tablecmds.c.

References generate_unaccent_rules::action, CacheMemoryContext, OnCommitItem::creating_subid, OnCommitItem::deleting_subid, GetCurrentSubTransactionId(), InvalidSubTransactionId, lcons(), MemoryContextSwitchTo(), OnCommitItem::oncommit, ONCOMMIT_NOOP, ONCOMMIT_PRESERVE_ROWS, palloc(), and OnCommitItem::relid.

Referenced by heap_create_with_catalog().

16227 {
16228  OnCommitItem *oc;
16229  MemoryContext oldcxt;
16230 
16231  /*
16232  * We needn't bother registering the relation unless there is an ON COMMIT
16233  * action we need to take.
16234  */
16236  return;
16237 
16239 
16240  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
16241  oc->relid = relid;
16242  oc->oncommit = action;
16245 
16246  /*
16247  * We use lcons() here so that ON COMMIT actions are processed in reverse
16248  * order of registration. That might not be essential but it seems
16249  * reasonable.
16250  */
16251  on_commits = lcons(oc, on_commits);
16252 
16253  MemoryContextSwitchTo(oldcxt);
16254 }
OnCommitAction oncommit
Definition: tablecmds.c:110
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
SubTransactionId creating_subid
Definition: tablecmds.c:119
static List * on_commits
Definition: tablecmds.c:123
SubTransactionId deleting_subid
Definition: tablecmds.c:120
List * lcons(void *datum, List *list)
Definition: list.c:468
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
#define InvalidSubTransactionId
Definition: c.h:593
void * palloc(Size size)
Definition: mcxt.c:1062
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ remove_on_commit_action()

void remove_on_commit_action ( Oid  relid)

Definition at line 16262 of file tablecmds.c.

References OnCommitItem::deleting_subid, GetCurrentSubTransactionId(), lfirst, and OnCommitItem::relid.

Referenced by heap_drop_with_catalog().

16263 {
16264  ListCell *l;
16265 
16266  foreach(l, on_commits)
16267  {
16268  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
16269 
16270  if (oc->relid == relid)
16271  {
16273  break;
16274  }
16275  }
16276 }
static List * on_commits
Definition: tablecmds.c:123
SubTransactionId deleting_subid
Definition: tablecmds.c:120
#define lfirst(lc)
Definition: pg_list.h:169
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723

◆ RemoveRelations()

void RemoveRelations ( DropStmt drop)

Definition at line 1307 of file tablecmds.c.

References AcceptInvalidationMessages(), AccessExclusiveLock, add_exact_object_address(), Assert, DropStmt::behavior, ObjectAddress::classId, DropRelationCallbackState::concurrent, DropStmt::concurrent, DROP_CASCADE, DropErrorMsgNonExistent(), elog, ereport, errcode(), errmsg(), ERROR, free_object_addresses(), get_rel_persistence(), get_rel_relkind(), DropRelationCallbackState::heapOid, InvalidOid, lfirst, list_length(), makeRangeVarFromNameList(), DropStmt::missing_ok, new_object_addresses(), OBJECT_FOREIGN_TABLE, OBJECT_INDEX, OBJECT_MATVIEW, OBJECT_SEQUENCE, OBJECT_TABLE, OBJECT_VIEW, ObjectAddress::objectId, DropStmt::objects, ObjectAddress::objectSubId, OidIsValid, DropRelationCallbackState::partParentOid, PERFORM_DELETION_CONCURRENTLY, performMultipleDeletions(), RangeVarCallbackForDropRelation(), RangeVarGetRelidExtended(), DropRelationCallbackState::relkind, RangeVar::relname, DropStmt::removeType, RVR_MISSING_OK, and ShareUpdateExclusiveLock.

Referenced by ExecDropStmt().

1308 {
1309  ObjectAddresses *objects;
1310  char relkind;
1311  ListCell *cell;
1312  int flags = 0;
1313  LOCKMODE lockmode = AccessExclusiveLock;
1314 
1315  /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1316  if (drop->concurrent)
1317  {
1318  /*
1319  * Note that for temporary relations this lock may get upgraded later
1320  * on, but as no other session can access a temporary relation, this
1321  * is actually fine.
1322  */
1323  lockmode = ShareUpdateExclusiveLock;
1324  Assert(drop->removeType == OBJECT_INDEX);
1325  if (list_length(drop->objects) != 1)
1326  ereport(ERROR,
1327  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1328  errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1329  if (drop->behavior == DROP_CASCADE)
1330  ereport(ERROR,
1331  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1332  errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1333  }
1334 
1335  /*
1336  * First we identify all the relations, then we delete them in a single
1337  * performMultipleDeletions() call. This is to avoid unwanted DROP
1338  * RESTRICT errors if one of the relations depends on another.
1339  */
1340 
1341  /* Determine required relkind */
1342  switch (drop->removeType)
1343  {
1344  case OBJECT_TABLE:
1345  relkind = RELKIND_RELATION;
1346  break;
1347 
1348  case OBJECT_INDEX:
1349  relkind = RELKIND_INDEX;
1350  break;
1351 
1352  case OBJECT_SEQUENCE:
1353  relkind = RELKIND_SEQUENCE;
1354  break;
1355 
1356  case OBJECT_VIEW:
1357  relkind = RELKIND_VIEW;
1358  break;
1359 
1360  case OBJECT_MATVIEW:
1361  relkind = RELKIND_MATVIEW;
1362  break;
1363 
1364  case OBJECT_FOREIGN_TABLE:
1365  relkind = RELKIND_FOREIGN_TABLE;
1366  break;
1367 
1368  default:
1369  elog(ERROR, "unrecognized drop object type: %d",
1370  (int) drop->removeType);
1371  relkind = 0; /* keep compiler quiet */
1372  break;
1373  }
1374 
1375  /* Lock and validate each relation; build a list of object addresses */
1376  objects = new_object_addresses();
1377 
1378  foreach(cell, drop->objects)
1379  {
1380  RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1381  Oid relOid;
1382  ObjectAddress obj;
1384 
1385  /*
1386  * These next few steps are a great deal like relation_openrv, but we
1387  * don't bother building a relcache entry since we don't need it.
1388  *
1389  * Check for shared-cache-inval messages before trying to access the
1390  * relation. This is needed to cover the case where the name
1391  * identifies a rel that has been dropped and recreated since the
1392  * start of our transaction: if we don't flush the old syscache entry,
1393  * then we'll latch onto that entry and suffer an error later.
1394  */
1396 
1397  /* Look up the appropriate relation using namespace search. */
1398  state.relkind = relkind;
1399  state.heapOid = InvalidOid;
1400  state.partParentOid = InvalidOid;
1401  state.concurrent = drop->concurrent;
1402  relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1404  (void *) &state);
1405 
1406  /* Not there? */
1407  if (!OidIsValid(relOid))
1408  {
1409  DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1410  continue;
1411  }
1412 
1413  /*
1414  * Decide if concurrent mode needs to be used here or not. The
1415  * relation persistence cannot be known without its OID.
1416  */
1417  if (drop->concurrent &&
1418  get_rel_persistence(relOid) != RELPERSISTENCE_TEMP)
1419  {
1420  Assert(list_length(drop->objects) == 1 &&
1421  drop->removeType == OBJECT_INDEX);
1423  }
1424 
1425  /*
1426  * Concurrent index drop cannot be used with partitioned indexes,
1427  * either.
1428  */
1429  if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1430  get_rel_relkind(relOid) == RELKIND_PARTITIONED_INDEX)
1431  ereport(ERROR,
1432  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1433  errmsg("cannot drop partitioned index \"%s\" concurrently",
1434  rel->relname)));
1435 
1436  /* OK, we're ready to delete this one */
1437  obj.classId = RelationRelationId;
1438  obj.objectId = relOid;
1439  obj.objectSubId = 0;
1440 
1441  add_exact_object_address(&obj, objects);
1442  }
1443 
1444  performMultipleDeletions(objects, drop->behavior, flags);
1445 
1446  free_object_addresses(objects);
1447 }
void AcceptInvalidationMessages(void)
Definition: inval.c:725
int LOCKMODE
Definition: lockdefs.h:26
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1974
List * objects
Definition: parsenodes.h:2766
bool missing_ok
Definition: parsenodes.h:2769
int errcode(int sqlerrcode)
Definition: elog.c:698
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3107
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2485
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2430
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2725
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
ObjectType removeType
Definition: parsenodes.h:2767
#define PERFORM_DELETION_CONCURRENTLY
Definition: dependency.h:134
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:46
bool concurrent
Definition: parsenodes.h:2770
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:237
DropBehavior behavior
Definition: parsenodes.h:2768
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:1456
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
Definition: regguts.h:317
static int list_length(const List *l)
Definition: pg_list.h:149
char get_rel_persistence(Oid relid)
Definition: lsyscache.c:2049
#define AccessExclusiveLock
Definition: lockdefs.h:45
static void DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
Definition: tablecmds.c:1232
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:372
Definition: pg_list.h:50

◆ renameatt()

ObjectAddress renameatt ( RenameStmt stmt)

Definition at line 3541 of file tablecmds.c.

References AccessExclusiveLock, attnum, RenameStmt::behavior, ereport, errmsg(), RangeVar::inh, InvalidObjectAddress, RenameStmt::missing_ok, RenameStmt::newname, NOTICE, ObjectAddressSubSet, OidIsValid, RangeVarCallbackForRenameAttribute(), RangeVarGetRelidExtended(), RenameStmt::relation, OnCommitItem::relid, RangeVar::relname, renameatt_internal(), RVR_MISSING_OK, and RenameStmt::subname.

Referenced by ExecRenameStmt().

3542 {
3543  Oid relid;
3545  ObjectAddress address;
3546 
3547  /* lock level taken here should match renameatt_internal */
3549  stmt->missing_ok ? RVR_MISSING_OK : 0,
3551  NULL);
3552 
3553  if (!OidIsValid(relid))
3554  {
3555  ereport(NOTICE,
3556  (errmsg("relation \"%s\" does not exist, skipping",
3557  stmt->relation->relname)));
3558  return InvalidObjectAddress;
3559  }
3560 
3561  attnum =
3562  renameatt_internal(relid,
3563  stmt->subname, /* old att name */
3564  stmt->newname, /* new att name */
3565  stmt->relation->inh, /* recursive? */
3566  false, /* recursing? */
3567  0, /* expected inhcount */
3568  stmt->behavior);
3569 
3570  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3571 
3572  return address;
3573 }
char * subname
Definition: parsenodes.h:3059
char * newname
Definition: parsenodes.h:3061
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:3063
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:237
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:3057
int16 attnum
Definition: pg_attribute.h:83
#define ereport(elevel,...)
Definition: elog.h:157
#define NOTICE
Definition: elog.h:37
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3521
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:3376
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:909
DropBehavior behavior
Definition: parsenodes.h:3062
int16 AttrNumber
Definition: attnum.h:21

◆ RenameConstraint()

ObjectAddress RenameConstraint ( RenameStmt stmt)

Definition at line 3685 of file tablecmds.c.

References AccessExclusiveLock, castNode, checkDomainOwner(), elog, ereport, errmsg(), ERROR, HeapTupleIsValid, RangeVar::inh, InvalidObjectAddress, InvalidOid, makeTypeNameFromNameList(), RenameStmt::missing_ok, RenameStmt::newname, NoLock, NOTICE, RenameStmt::object, OBJECT_DOMCONSTRAINT, ObjectIdGetDatum, OidIsValid, RangeVarCallbackForRenameAttribute(), RangeVarGetRelidExtended(), RenameStmt::relation, ReleaseSysCache(), OnCommitItem::relid, RangeVar::relname, rename_constraint_internal(), RenameStmt::renameType, RowExclusiveLock, RVR_MISSING_OK, SearchSysCache1(), RenameStmt::subname, table_close(), table_open(), typenameTypeId(), and TYPEOID.

Referenced by ExecRenameStmt().

3686 {
3687  Oid relid = InvalidOid;
3688  Oid typid = InvalidOid;
3689 
3690  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3691  {
3692  Relation rel;
3693  HeapTuple tup;
3694 
3696  rel = table_open(TypeRelationId, RowExclusiveLock);
3697  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3698  if (!HeapTupleIsValid(tup))
3699  elog(ERROR, "cache lookup failed for type %u", typid);
3700  checkDomainOwner(tup);
3701  ReleaseSysCache(tup);
3702  table_close(rel, NoLock);
3703  }
3704  else
3705  {
3706  /* lock level taken here should match rename_constraint_internal */
3708  stmt->missing_ok ? RVR_MISSING_OK : 0,
3710  NULL);
3711  if (!OidIsValid(relid))
3712  {
3713  ereport(NOTICE,
3714  (errmsg("relation \"%s\" does not exist, skipping",
3715  stmt->relation->relname)));
3716  return InvalidObjectAddress;
3717  }
3718  }
3719 
3720  return
3721  rename_constraint_internal(relid, typid,
3722  stmt->subname,
3723  stmt->newname,
3724  (stmt->relation &&
3725  stmt->relation->inh), /* recursive? */
3726  false, /* recursing? */
3727  0 /* expected inhcount */ );
3728 
3729 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
char * subname
Definition: parsenodes.h:3059
ObjectType renameType
Definition: parsenodes.h:3055
#define castNode(_type_, nodeptr)
Definition: nodes.h:605
static ObjectAddress rename_constraint_internal(Oid myrelid, Oid mytypid, const char *oldconname, const char *newconname, bool recurse, bool recursing, int expected_parents)
Definition: tablecmds.c:3579
char * newname
Definition: parsenodes.h:3061
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:3063
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Node * object
Definition: parsenodes.h:3058
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:237
bool inh
Definition: primnodes.h:69
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
RangeVar * relation
Definition: parsenodes.h:3057
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3521
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3425
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:456
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ RenameRelation()

ObjectAddress RenameRelation ( RenameStmt stmt)

Definition at line 3736 of file tablecmds.c.

References AccessExclusiveLock, ereport, errmsg(), InvalidObjectAddress, RenameStmt::missing_ok, NOTICE, OBJECT_INDEX, ObjectAddressSet, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetRelidExtended(), RenameStmt::relation, OnCommitItem::relid, RenameRelationInternal(), RenameStmt::renameType, RVR_MISSING_OK, and ShareUpdateExclusiveLock.

Referenced by ExecRenameStmt().

3737 {
3738  bool is_index = stmt->renameType == OBJECT_INDEX;
3739  Oid relid;
3740  ObjectAddress address;
3741 
3742  /*
3743  * Grab an exclusive lock on the target table, index, sequence, view,
3744  * materialized view, or foreign table, which we will NOT release until
3745  * end of transaction.
3746  *
3747  * Lock level used here should match RenameRelationInternal, to avoid lock
3748  * escalation.
3749  */
3750  relid = RangeVarGetRelidExtended(stmt->relation,
3752  stmt->missing_ok ? RVR_MISSING_OK : 0,
3754  (void *) stmt);
3755 
3756  if (!OidIsValid(relid))
3757  {
3758  ereport(NOTICE,
3759  (errmsg("relation \"%s\" does not exist, skipping",
3760  stmt->relation->relname)));
3761  return InvalidObjectAddress;
3762  }
3763 
3764  /* Do the work */
3765  RenameRelationInternal(relid, stmt->newname, false, is_index);
3766 
3767  ObjectAddressSet(address, RelationRelationId, relid);
3768 
3769  return address;
3770 }
ObjectType renameType
Definition: parsenodes.h:3055
char * newname
Definition: parsenodes.h:3061
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:3063
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:16540
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:237
RangeVar * relation
Definition: parsenodes.h:3057
#define ereport(elevel,...)
Definition: elog.h:157
#define NOTICE
Definition: elog.h:37
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:909
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3776

◆ RenameRelationInternal()

void RenameRelationInternal ( Oid  myrelid,
const char *  newrelname,
bool  is_internal,
bool  is_index 
)

Definition at line 3776 of file tablecmds.c.

References AccessExclusiveLock, CatalogTupleUpdate(), elog, ereport, errcode(), errmsg(), ERROR, get_index_constraint(), get_relname_relid(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHookArg, namestrcpy(), NoLock, ObjectIdGetDatum, OidIsValid, RelationData::rd_rel, relation_close(), relation_open(), RelationGetNamespace, RELOID, RenameConstraintById(), RenameTypeInternal(), RowExclusiveLock, SearchSysCacheCopy1, ShareUpdateExclusiveLock, HeapTupleData::t_self, table_close(), and table_open().

Referenced by ATExecAddIndexConstraint(), finish_heap_swap(), rename_constraint_internal(), RenameRelation(), and RenameType().

3777 {
3778  Relation targetrelation;
3779  Relation relrelation; /* for RELATION relation */
3780  HeapTuple reltup;
3781  Form_pg_class relform;
3782  Oid namespaceId;
3783 
3784  /*
3785  * Grab a lock on the target relation, which we will NOT release until end
3786  * of transaction. We need at least a self-exclusive lock so that
3787  * concurrent DDL doesn't overwrite the rename if they start updating
3788  * while still seeing the old version. The lock also guards against
3789  * triggering relcache reloads in concurrent sessions, which might not
3790  * handle this information changing under them. For indexes, we can use a
3791  * reduced lock level because RelationReloadIndexInfo() handles indexes
3792  * specially.
3793  */
3794  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
3795  namespaceId = RelationGetNamespace(targetrelation);
3796 
3797  /*
3798  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3799  */
3800  relrelation = table_open(RelationRelationId, RowExclusiveLock);
3801 
3802  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3803  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3804  elog(ERROR, "cache lookup failed for relation %u", myrelid);
3805  relform = (Form_pg_class) GETSTRUCT(reltup);
3806 
3807  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3808  ereport(ERROR,
3809  (errcode(ERRCODE_DUPLICATE_TABLE),
3810  errmsg("relation \"%s\" already exists",
3811  newrelname)));
3812 
3813  /*
3814  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
3815  * because it's a copy...)
3816  */
3817  namestrcpy(&(relform->relname), newrelname);
3818 
3819  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3820 
3821  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
3822  InvalidOid, is_internal);
3823 
3824  heap_freetuple(reltup);
3825  table_close(relrelation, RowExclusiveLock);
3826 
3827  /*
3828  * Also rename the associated type, if any.
3829  */
3830  if (OidIsValid(targetrelation->rd_rel->reltype))
3831  RenameTypeInternal(targetrelation->rd_rel->reltype,
3832  newrelname, namespaceId);
3833 
3834  /*
3835  * Also rename the associated constraint, if any.
3836  */
3837  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3838  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3839  {
3840  Oid constraintId = get_index_constraint(myrelid);
3841 
3842  if (OidIsValid(constraintId))
3843  RenameConstraintById(constraintId, newrelname);
3844  }
3845 
3846  /*
3847  * Close rel, but keep lock!
3848  */
3849  relation_close(targetrelation, NoLock);
3850 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
void namestrcpy(Name name, const char *str)
Definition: name.c:233
int errcode(int sqlerrcode)
Definition: elog.c:698
Form_pg_class rd_rel
Definition: rel.h:109
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
Definition: objectaccess.h:178
void RenameConstraintById(Oid conId, const char *newname)
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1856
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:911
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:741
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetNamespace(relation)
Definition: rel.h:518

◆ ResetRelRewrite()

void ResetRelRewrite ( Oid  myrelid)

Definition at line 3856 of file tablecmds.c.

References CatalogTupleUpdate(), elog, ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvalidOid, ObjectIdGetDatum, RELOID, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

Referenced by finish_heap_swap().

3857 {
3858  Relation relrelation; /* for RELATION relation */
3859  HeapTuple reltup;
3860  Form_pg_class relform;
3861 
3862  /*
3863  * Find relation's pg_class tuple.
3864  */
3865  relrelation = table_open(RelationRelationId, RowExclusiveLock);
3866 
3867  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3868  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3869  elog(ERROR, "cache lookup failed for relation %u", myrelid);
3870  relform = (Form_pg_class) GETSTRUCT(reltup);
3871 
3872  /*
3873  * Update pg_class tuple.
3874  */
3875  relform->relrewrite = InvalidOid;
3876 
3877  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3878 
3879  heap_freetuple(reltup);
3880  table_close(relrelation, RowExclusiveLock);
3881 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
#define elog(elevel,...)
Definition: elog.h:232
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

◆ SetRelationHasSubclass()

void SetRelationHasSubclass ( Oid  relationId,
bool  relhassubclass 
)

Definition at line 3187 of file tablecmds.c.

References CacheInvalidateRelcacheByTuple(), CatalogTupleUpdate(), elog, ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, ObjectIdGetDatum, RELOID, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

Referenced by acquire_inherited_sample_rows(), index_create(), IndexSetParentIndex(), and StoreCatalogInheritance1().

3188 {
3189  Relation relationRelation;
3190  HeapTuple tuple;
3191  Form_pg_class classtuple;
3192 
3193  /*
3194  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3195  */
3196  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3197  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3198  if (!HeapTupleIsValid(tuple))
3199  elog(ERROR, "cache lookup failed for relation %u", relationId);
3200  classtuple = (Form_pg_class) GETSTRUCT(tuple);
3201 
3202  if (classtuple->relhassubclass != relhassubclass)
3203  {
3204  classtuple->relhassubclass = relhassubclass;
3205  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3206  }
3207  else
3208  {
3209  /* no need to change tuple, but force relcache rebuild anyway */
3211  }
3212 
3213  heap_freetuple(tuple);
3214  table_close(relationRelation, RowExclusiveLock);
3215 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
#define elog(elevel,...)
Definition: elog.h:232
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1378
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

◆ SetRelationTableSpace()

void SetRelationTableSpace ( Relation  rel,
Oid  newTableSpaceId,
Oid  newRelFileNode 
)

Definition at line 3285 of file tablecmds.c.

References Assert, CatalogTupleUpdate(), changeDependencyOnTablespace(), CheckRelationTableSpaceMove(), elog, ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvalidOid, MyDatabaseTableSpace, ObjectIdGetDatum, OidIsValid, RelationData::rd_rel, RelationGetRelid, RELOID, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

Referenced by ATExecSetTableSpace(), ATExecSetTableSpaceNoStorage(), and reindex_index().

3288 {
3289  Relation pg_class;
3290  HeapTuple tuple;
3291  Form_pg_class rd_rel;
3292  Oid reloid = RelationGetRelid(rel);
3293 
3294  Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3295 
3296  /* Get a modifiable copy of the relation's pg_class row. */
3297  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3298 
3299  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
3300  if (!HeapTupleIsValid(tuple))
3301  elog(ERROR, "cache lookup failed for relation %u", reloid);
3302  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3303 
3304  /* Update the pg_class row. */
3305  rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3306  InvalidOid : newTableSpaceId;
3307  if (OidIsValid(newRelFileNode))
3308  rd_rel->relfilenode = newRelFileNode;
3309  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3310 
3311  /*
3312  * Record dependency on tablespace. This is only required for relations
3313  * that have no physical storage.
3314  */
3315  if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3316  changeDependencyOnTablespace(RelationRelationId, reloid,
3317  rd_rel->reltablespace);
3318 
3319  heap_freetuple(tuple);
3320  table_close(pg_class, RowExclusiveLock);
3321 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
Form_pg_class rd_rel
Definition: rel.h:109
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
Oid MyDatabaseTableSpace
Definition: globals.c:90
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
ItemPointerData t_self
Definition: htup.h:65
bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
Definition: tablecmds.c:3228
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
void changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId)
Definition: pg_shdepend.c:380
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
#define elog(elevel,...)
Definition: elog.h:232
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:477