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, RelFileNumber newRelFilenumber)
 
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 RangeVarCallbackMaintainsTable (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
bool has_partition_ancestor_privs (Oid relid, Oid userid, AclMode acl)
 
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 16420 of file tablecmds.c.

16424 {
16425  HeapTuple classTup;
16426  Form_pg_class classForm;
16427  ObjectAddress thisobj;
16428  bool already_done = false;
16429 
16430  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
16431  if (!HeapTupleIsValid(classTup))
16432  elog(ERROR, "cache lookup failed for relation %u", relOid);
16433  classForm = (Form_pg_class) GETSTRUCT(classTup);
16434 
16435  Assert(classForm->relnamespace == oldNspOid);
16436 
16437  thisobj.classId = RelationRelationId;
16438  thisobj.objectId = relOid;
16439  thisobj.objectSubId = 0;
16440 
16441  /*
16442  * If the object has already been moved, don't move it again. If it's
16443  * already in the right place, don't move it, but still fire the object
16444  * access hook.
16445  */
16446  already_done = object_address_present(&thisobj, objsMoved);
16447  if (!already_done && oldNspOid != newNspOid)
16448  {
16449  /* check for duplicate name (more friendly than unique-index failure) */
16450  if (get_relname_relid(NameStr(classForm->relname),
16451  newNspOid) != InvalidOid)
16452  ereport(ERROR,
16453  (errcode(ERRCODE_DUPLICATE_TABLE),
16454  errmsg("relation \"%s\" already exists in schema \"%s\"",
16455  NameStr(classForm->relname),
16456  get_namespace_name(newNspOid))));
16457 
16458  /* classTup is a copy, so OK to scribble on */
16459  classForm->relnamespace = newNspOid;
16460 
16461  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
16462 
16463  /* Update dependency on schema if caller said so */
16464  if (hasDependEntry &&
16465  changeDependencyFor(RelationRelationId,
16466  relOid,
16467  NamespaceRelationId,
16468  oldNspOid,
16469  newNspOid) != 1)
16470  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
16471  NameStr(classForm->relname));
16472  }
16473  if (!already_done)
16474  {
16475  add_exact_object_address(&thisobj, objsMoved);
16476 
16477  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
16478  }
16479 
16480  heap_freetuple(classTup);
16481 }
#define NameStr(name)
Definition: c.h:730
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2641
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2581
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
Assert(fmt[strlen(fmt) - 1] !='\n')
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3331
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1867
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:456
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define InvalidOid
Definition: postgres_ext.h:36
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
@ RELOID
Definition: syscache.h:89

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().

◆ AlterTable()

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

Definition at line 4105 of file tablecmds.c.

4107 {
4108  Relation rel;
4109 
4110  /* Caller is required to provide an adequate lock. */
4111  rel = relation_open(context->relid, NoLock);
4112 
4113  CheckTableNotInUse(rel, "ALTER TABLE");
4114 
4115  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4116 }
#define NoLock
Definition: lockdefs.h:34
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
RangeVar * relation
Definition: parsenodes.h:2053
bool inh
Definition: primnodes.h:77
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:4018
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4449

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

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4179 of file tablecmds.c.

4180 {
4181  /*
4182  * This only works if we read catalog tables using MVCC snapshots.
4183  */
4184  ListCell *lcmd;
4186 
4187  foreach(lcmd, cmds)
4188  {
4189  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4190  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4191 
4192  switch (cmd->subtype)
4193  {
4194  /*
4195  * These subcommands rewrite the heap, so require full locks.
4196  */
4197  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4198  * to SELECT */
4199  case AT_SetAccessMethod: /* must rewrite heap */
4200  case AT_SetTableSpace: /* must rewrite heap */
4201  case AT_AlterColumnType: /* must rewrite heap */
4202  cmd_lockmode = AccessExclusiveLock;
4203  break;
4204 
4205  /*
4206  * These subcommands may require addition of toast tables. If
4207  * we add a toast table to a table currently being scanned, we
4208  * might miss data added to the new toast table by concurrent
4209  * insert transactions.
4210  */
4211  case AT_SetStorage: /* may add toast tables, see
4212  * ATRewriteCatalogs() */
4213  cmd_lockmode = AccessExclusiveLock;
4214  break;
4215 
4216  /*
4217  * Removing constraints can affect SELECTs that have been
4218  * optimized assuming the constraint holds true. See also
4219  * CloneFkReferenced.
4220  */
4221  case AT_DropConstraint: /* as DROP INDEX */
4222  case AT_DropNotNull: /* may change some SQL plans */
4223  cmd_lockmode = AccessExclusiveLock;
4224  break;
4225 
4226  /*
4227  * Subcommands that may be visible to concurrent SELECTs
4228  */
4229  case AT_DropColumn: /* change visible to SELECT */
4230  case AT_AddColumnToView: /* CREATE VIEW */
4231  case AT_DropOids: /* used to equiv to DropColumn */
4232  case AT_EnableAlwaysRule: /* may change SELECT rules */
4233  case AT_EnableReplicaRule: /* may change SELECT rules */
4234  case AT_EnableRule: /* may change SELECT rules */
4235  case AT_DisableRule: /* may change SELECT rules */
4236  cmd_lockmode = AccessExclusiveLock;
4237  break;
4238 
4239  /*
4240  * Changing owner may remove implicit SELECT privileges
4241  */
4242  case AT_ChangeOwner: /* change visible to SELECT */
4243  cmd_lockmode = AccessExclusiveLock;
4244  break;
4245 
4246  /*
4247  * Changing foreign table options may affect optimization.
4248  */
4249  case AT_GenericOptions:
4251  cmd_lockmode = AccessExclusiveLock;
4252  break;
4253 
4254  /*
4255  * These subcommands affect write operations only.
4256  */
4257  case AT_EnableTrig:
4258  case AT_EnableAlwaysTrig:
4259  case AT_EnableReplicaTrig:
4260  case AT_EnableTrigAll:
4261  case AT_EnableTrigUser:
4262  case AT_DisableTrig:
4263  case AT_DisableTrigAll:
4264  case AT_DisableTrigUser:
4265  cmd_lockmode = ShareRowExclusiveLock;
4266  break;
4267 
4268  /*
4269  * These subcommands affect write operations only. XXX
4270  * Theoretically, these could be ShareRowExclusiveLock.
4271  */
4272  case AT_ColumnDefault:
4274  case AT_AlterConstraint:
4275  case AT_AddIndex: /* from ADD CONSTRAINT */
4276  case AT_AddIndexConstraint:
4277  case AT_ReplicaIdentity:
4278  case AT_SetNotNull:
4279  case AT_EnableRowSecurity:
4280  case AT_DisableRowSecurity:
4281  case AT_ForceRowSecurity:
4282  case AT_NoForceRowSecurity:
4283  case AT_AddIdentity:
4284  case AT_DropIdentity:
4285  case AT_SetIdentity:
4286  case AT_DropExpression:
4287  case AT_SetCompression:
4288  cmd_lockmode = AccessExclusiveLock;
4289  break;
4290 
4291  case AT_AddConstraint:
4292  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4293  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4294  if (IsA(cmd->def, Constraint))
4295  {
4296  Constraint *con = (Constraint *) cmd->def;
4297 
4298  switch (con->contype)
4299  {
4300  case CONSTR_EXCLUSION:
4301  case CONSTR_PRIMARY:
4302  case CONSTR_UNIQUE:
4303 
4304  /*
4305  * Cases essentially the same as CREATE INDEX. We
4306  * could reduce the lock strength to ShareLock if
4307  * we can work out how to allow concurrent catalog
4308  * updates. XXX Might be set down to
4309  * ShareRowExclusiveLock but requires further
4310  * analysis.
4311  */
4312  cmd_lockmode = AccessExclusiveLock;
4313  break;
4314  case CONSTR_FOREIGN:
4315 
4316  /*
4317  * We add triggers to both tables when we add a
4318  * Foreign Key, so the lock level must be at least
4319  * as strong as CREATE TRIGGER.
4320  */
4321  cmd_lockmode = ShareRowExclusiveLock;
4322  break;
4323 
4324  default:
4325  cmd_lockmode = AccessExclusiveLock;
4326  }
4327  }
4328  break;
4329 
4330  /*
4331  * These subcommands affect inheritance behaviour. Queries
4332  * started before us will continue to see the old inheritance
4333  * behaviour, while queries started after we commit will see
4334  * new behaviour. No need to prevent reads or writes to the
4335  * subtable while we hook it up though. Changing the TupDesc
4336  * may be a problem, so keep highest lock.
4337  */
4338  case AT_AddInherit:
4339  case AT_DropInherit:
4340  cmd_lockmode = AccessExclusiveLock;
4341  break;
4342 
4343  /*
4344  * These subcommands affect implicit row type conversion. They
4345  * have affects similar to CREATE/DROP CAST on queries. don't
4346  * provide for invalidating parse trees as a result of such
4347  * changes, so we keep these at AccessExclusiveLock.
4348  */
4349  case AT_AddOf:
4350  case AT_DropOf:
4351  cmd_lockmode = AccessExclusiveLock;
4352  break;
4353 
4354  /*
4355  * Only used by CREATE OR REPLACE VIEW which must conflict
4356  * with an SELECTs currently using the view.
4357  */
4358  case AT_ReplaceRelOptions:
4359  cmd_lockmode = AccessExclusiveLock;
4360  break;
4361 
4362  /*
4363  * These subcommands affect general strategies for performance
4364  * and maintenance, though don't change the semantic results
4365  * from normal data reads and writes. Delaying an ALTER TABLE
4366  * behind currently active writes only delays the point where
4367  * the new strategy begins to take effect, so there is no
4368  * benefit in waiting. In this case the minimum restriction
4369  * applies: we don't currently allow concurrent catalog
4370  * updates.
4371  */
4372  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4373  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4374  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4375  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4376  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4377  cmd_lockmode = ShareUpdateExclusiveLock;
4378  break;
4379 
4380  case AT_SetLogged:
4381  case AT_SetUnLogged:
4382  cmd_lockmode = AccessExclusiveLock;
4383  break;
4384 
4385  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4386  cmd_lockmode = ShareUpdateExclusiveLock;
4387  break;
4388 
4389  /*
4390  * Rel options are more complex than first appears. Options
4391  * are set here for tables, views and indexes; for historical
4392  * reasons these can all be used with ALTER TABLE, so we can't
4393  * decide between them using the basic grammar.
4394  */
4395  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4396  * getTables() */
4397  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4398  * getTables() */
4399  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4400  break;
4401 
4402  case AT_AttachPartition:
4403  cmd_lockmode = ShareUpdateExclusiveLock;
4404  break;
4405 
4406  case AT_DetachPartition:
4407  if (((PartitionCmd *) cmd->def)->concurrent)
4408  cmd_lockmode = ShareUpdateExclusiveLock;
4409  else
4410  cmd_lockmode = AccessExclusiveLock;
4411  break;
4412 
4414  cmd_lockmode = ShareUpdateExclusiveLock;
4415  break;
4416 
4417  case AT_CheckNotNull:
4418 
4419  /*
4420  * This only examines the table's schema; but lock must be
4421  * strong enough to prevent concurrent DROP NOT NULL.
4422  */
4423  cmd_lockmode = AccessShareLock;
4424  break;
4425 
4426  default: /* oops */
4427  elog(ERROR, "unrecognized alter table type: %d",
4428  (int) cmd->subtype);
4429  break;
4430  }
4431 
4432  /*
4433  * Take the greatest lockmode from any subcommand
4434  */
4435  if (cmd_lockmode > lockmode)
4436  lockmode = cmd_lockmode;
4437  }
4438 
4439  return lockmode;
4440 }
int LOCKMODE
Definition: lockdefs.h:26
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define ShareRowExclusiveLock
Definition: lockdefs.h:41
#define AccessShareLock
Definition: lockdefs.h:36
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
@ CONSTR_FOREIGN
Definition: parsenodes.h:2420
@ CONSTR_UNIQUE
Definition: parsenodes.h:2418
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2419
@ CONSTR_PRIMARY
Definition: parsenodes.h:2417
@ AT_AddIndexConstraint
Definition: parsenodes.h:2082
@ AT_DropOf
Definition: parsenodes.h:2113
@ AT_CheckNotNull
Definition: parsenodes.h:2068
@ AT_SetOptions
Definition: parsenodes.h:2070
@ AT_DropIdentity
Definition: parsenodes.h:2125
@ AT_DisableTrigUser
Definition: parsenodes.h:2105
@ AT_DropNotNull
Definition: parsenodes.h:2065
@ AT_AddOf
Definition: parsenodes.h:2112
@ AT_ResetOptions
Definition: parsenodes.h:2071
@ AT_ReplicaIdentity
Definition: parsenodes.h:2114
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2097
@ AT_EnableRowSecurity
Definition: parsenodes.h:2115
@ AT_AddColumnToView
Definition: parsenodes.h:2062
@ AT_ResetRelOptions
Definition: parsenodes.h:2096
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2100
@ AT_DropOids
Definition: parsenodes.h:2092
@ AT_SetIdentity
Definition: parsenodes.h:2124
@ AT_SetUnLogged
Definition: parsenodes.h:2091
@ AT_DisableTrig
Definition: parsenodes.h:2101
@ AT_SetCompression
Definition: parsenodes.h:2073
@ AT_DropExpression
Definition: parsenodes.h:2067
@ AT_AddIndex
Definition: parsenodes.h:2075
@ AT_EnableReplicaRule
Definition: parsenodes.h:2108
@ AT_DropConstraint
Definition: parsenodes.h:2083
@ AT_SetNotNull
Definition: parsenodes.h:2066
@ AT_ClusterOn
Definition: parsenodes.h:2088
@ AT_AddIdentity
Definition: parsenodes.h:2123
@ AT_ForceRowSecurity
Definition: parsenodes.h:2117
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2107
@ AT_SetAccessMethod
Definition: parsenodes.h:2093
@ AT_AlterColumnType
Definition: parsenodes.h:2085
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2122
@ AT_AddInherit
Definition: parsenodes.h:2110
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2079
@ AT_EnableTrig
Definition: parsenodes.h:2098
@ AT_DropColumn
Definition: parsenodes.h:2074
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2086
@ AT_DisableTrigAll
Definition: parsenodes.h:2103
@ AT_EnableRule
Definition: parsenodes.h:2106
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2118
@ AT_DetachPartition
Definition: parsenodes.h:2121
@ AT_SetStatistics
Definition: parsenodes.h:2069
@ AT_AttachPartition
Definition: parsenodes.h:2120
@ AT_AddConstraint
Definition: parsenodes.h:2077
@ AT_DropInherit
Definition: parsenodes.h:2111
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2099
@ AT_SetLogged
Definition: parsenodes.h:2090
@ AT_SetStorage
Definition: parsenodes.h:2072
@ AT_DisableRule
Definition: parsenodes.h:2109
@ AT_DisableRowSecurity
Definition: parsenodes.h:2116
@ AT_SetRelOptions
Definition: parsenodes.h:2095
@ AT_ChangeOwner
Definition: parsenodes.h:2087
@ AT_EnableTrigUser
Definition: parsenodes.h:2104
@ AT_ReAddConstraint
Definition: parsenodes.h:2078
@ AT_SetTableSpace
Definition: parsenodes.h:2094
@ AT_GenericOptions
Definition: parsenodes.h:2119
@ AT_ColumnDefault
Definition: parsenodes.h:2063
@ AT_CookedColumnDefault
Definition: parsenodes.h:2064
@ AT_AlterConstraint
Definition: parsenodes.h:2080
@ AT_EnableTrigAll
Definition: parsenodes.h:2102
@ AT_DropCluster
Definition: parsenodes.h:2089
@ AT_ValidateConstraint
Definition: parsenodes.h:2081
@ AT_AddColumn
Definition: parsenodes.h:2061
#define lfirst(lc)
Definition: pg_list.h:172
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2109
AlterTableType subtype
Definition: parsenodes.h:2139
ConstrType contype
Definition: parsenodes.h:2444
Definition: pg_list.h:54

References AccessExclusiveLock, AccessShareLock, AlterTableGetRelOptionsLockLevel(), AT_AddColumn, AT_AddColumnToView, AT_AddConstraint, 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().

◆ AlterTableInternal()

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

Definition at line 4134 of file tablecmds.c.

4135 {
4136  Relation rel;
4137  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4138 
4139  rel = relation_open(relid, lockmode);
4140 
4142 
4143  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4144 }
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4179

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4046 of file tablecmds.c.

4047 {
4048  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4049  stmt->missing_ok ? RVR_MISSING_OK : 0,
4051  (void *) stmt);
4052 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:239
@ RVR_MISSING_OK
Definition: namespace.h:71
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:16961

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

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 14487 of file tablecmds.c.

14488 {
14489  List *relations = NIL;
14490  ListCell *l;
14491  ScanKeyData key[1];
14492  Relation rel;
14493  TableScanDesc scan;
14494  HeapTuple tuple;
14495  Oid orig_tablespaceoid;
14496  Oid new_tablespaceoid;
14497  List *role_oids = roleSpecsToIds(stmt->roles);
14498 
14499  /* Ensure we were not asked to move something we can't */
14500  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
14501  stmt->objtype != OBJECT_MATVIEW)
14502  ereport(ERROR,
14503  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14504  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
14505 
14506  /* Get the orig and new tablespace OIDs */
14507  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
14508  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
14509 
14510  /* Can't move shared relations in to or out of pg_global */
14511  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
14512  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
14513  new_tablespaceoid == GLOBALTABLESPACE_OID)
14514  ereport(ERROR,
14515  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14516  errmsg("cannot move relations in to or out of pg_global tablespace")));
14517 
14518  /*
14519  * Must have CREATE rights on the new tablespace, unless it is the
14520  * database default tablespace (which all users implicitly have CREATE
14521  * rights on).
14522  */
14523  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
14524  {
14525  AclResult aclresult;
14526 
14527  aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
14528  ACL_CREATE);
14529  if (aclresult != ACLCHECK_OK)
14530  aclcheck_error(aclresult, OBJECT_TABLESPACE,
14531  get_tablespace_name(new_tablespaceoid));
14532  }
14533 
14534  /*
14535  * Now that the checks are done, check if we should set either to
14536  * InvalidOid because it is our database's default tablespace.
14537  */
14538  if (orig_tablespaceoid == MyDatabaseTableSpace)
14539  orig_tablespaceoid = InvalidOid;
14540 
14541  if (new_tablespaceoid == MyDatabaseTableSpace)
14542  new_tablespaceoid = InvalidOid;
14543 
14544  /* no-op */
14545  if (orig_tablespaceoid == new_tablespaceoid)
14546  return new_tablespaceoid;
14547 
14548  /*
14549  * Walk the list of objects in the tablespace and move them. This will
14550  * only find objects in our database, of course.
14551  */
14552  ScanKeyInit(&key[0],
14553  Anum_pg_class_reltablespace,
14554  BTEqualStrategyNumber, F_OIDEQ,
14555  ObjectIdGetDatum(orig_tablespaceoid));
14556 
14557  rel = table_open(RelationRelationId, AccessShareLock);
14558  scan = table_beginscan_catalog(rel, 1, key);
14559  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
14560  {
14561  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
14562  Oid relOid = relForm->oid;
14563 
14564  /*
14565  * Do not move objects in pg_catalog as part of this, if an admin
14566  * really wishes to do so, they can issue the individual ALTER
14567  * commands directly.
14568  *
14569  * Also, explicitly avoid any shared tables, temp tables, or TOAST
14570  * (TOAST will be moved with the main table).
14571  */
14572  if (IsCatalogNamespace(relForm->relnamespace) ||
14573  relForm->relisshared ||
14574  isAnyTempNamespace(relForm->relnamespace) ||
14575  IsToastNamespace(relForm->relnamespace))
14576  continue;
14577 
14578  /* Only move the object type requested */
14579  if ((stmt->objtype == OBJECT_TABLE &&
14580  relForm->relkind != RELKIND_RELATION &&
14581  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
14582  (stmt->objtype == OBJECT_INDEX &&
14583  relForm->relkind != RELKIND_INDEX &&
14584  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
14585  (stmt->objtype == OBJECT_MATVIEW &&
14586  relForm->relkind != RELKIND_MATVIEW))
14587  continue;
14588 
14589  /* Check if we are only moving objects owned by certain roles */
14590  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
14591  continue;
14592 
14593  /*
14594  * Handle permissions-checking here since we are locking the tables
14595  * and also to avoid doing a bunch of work only to fail part-way. Note
14596  * that permissions will also be checked by AlterTableInternal().
14597  *
14598  * Caller must be considered an owner on the table to move it.
14599  */
14600  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
14602  NameStr(relForm->relname));
14603 
14604  if (stmt->nowait &&
14606  ereport(ERROR,
14607  (errcode(ERRCODE_OBJECT_IN_USE),
14608  errmsg("aborting because lock on relation \"%s.%s\" is not available",
14609  get_namespace_name(relForm->relnamespace),
14610  NameStr(relForm->relname))));
14611  else
14613 
14614  /* Add to our list of objects to move */
14615  relations = lappend_oid(relations, relOid);
14616  }
14617 
14618  table_endscan(scan);
14620 
14621  if (relations == NIL)
14622  ereport(NOTICE,
14623  (errcode(ERRCODE_NO_DATA_FOUND),
14624  errmsg("no matching relations in tablespace \"%s\" found",
14625  orig_tablespaceoid == InvalidOid ? "(database default)" :
14626  get_tablespace_name(orig_tablespaceoid))));
14627 
14628  /* Everything is locked, loop through and move all of the relations. */
14629  foreach(l, relations)
14630  {
14631  List *cmds = NIL;
14633 
14634  cmd->subtype = AT_SetTableSpace;
14635  cmd->name = stmt->new_tablespacename;
14636 
14637  cmds = lappend(cmds, cmd);
14638 
14640  /* OID is set by AlterTableInternal */
14641  AlterTableInternal(lfirst_oid(l), cmds, false);
14643  }
14644 
14645  return new_tablespaceoid;
14646 }
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2679
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3783
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:3984
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1478
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1432
#define OidIsValid(objectId)
Definition: c.h:759
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:202
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:184
#define NOTICE
Definition: elog.h:35
void EventTriggerAlterTableStart(Node *parsetree)
void EventTriggerAlterTableEnd(void)
Oid MyDatabaseTableSpace
Definition: globals.c:91
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1093
List * lappend(List *list, void *datum)
Definition: list.c:338
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:721
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:152
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:109
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1985
Oid GetUserId(void)
Definition: miscinit.c:502
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3238
#define makeNode(_type_)
Definition: nodes.h:176
ObjectType get_relkind_objtype(char relkind)
@ OBJECT_MATVIEW
Definition: parsenodes.h:1992
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2011
@ OBJECT_INDEX
Definition: parsenodes.h:1989
@ OBJECT_TABLE
Definition: parsenodes.h:2010
#define ACL_CREATE
Definition: parsenodes.h:92
#define NIL
Definition: pg_list.h:68
#define lfirst_oid(lc)
Definition: pg_list.h:174
unsigned int Oid
Definition: postgres_ext.h:31
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
@ ForwardScanDirection
Definition: sdir.h:28
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Definition: nodes.h:129
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:993
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4134
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1607

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_aclcheck(), OBJECT_INDEX, OBJECT_MATVIEW, object_ownercheck(), OBJECT_TABLE, OBJECT_TABLESPACE, ObjectIdGetDatum(), AlterTableMoveAllStmt::objtype, OidIsValid, AlterTableMoveAllStmt::orig_tablespacename, AlterTableMoveAllStmt::roles, roleSpecsToIds(), ScanKeyInit(), AlterTableCmd::subtype, table_beginscan_catalog(), table_close(), table_endscan(), and table_open().

Referenced by ProcessUtilitySlow().

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 16310 of file tablecmds.c.

16311 {
16312  Relation rel;
16313  Oid relid;
16314  Oid oldNspOid;
16315  Oid nspOid;
16316  RangeVar *newrv;
16317  ObjectAddresses *objsMoved;
16318  ObjectAddress myself;
16319 
16321  stmt->missing_ok ? RVR_MISSING_OK : 0,
16323  (void *) stmt);
16324 
16325  if (!OidIsValid(relid))
16326  {
16327  ereport(NOTICE,
16328  (errmsg("relation \"%s\" does not exist, skipping",
16329  stmt->relation->relname)));
16330  return InvalidObjectAddress;
16331  }
16332 
16333  rel = relation_open(relid, NoLock);
16334 
16335  oldNspOid = RelationGetNamespace(rel);
16336 
16337  /* If it's an owned sequence, disallow moving it by itself. */
16338  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
16339  {
16340  Oid tableId;
16341  int32 colId;
16342 
16343  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
16344  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
16345  ereport(ERROR,
16346  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16347  errmsg("cannot move an owned sequence into another schema"),
16348  errdetail("Sequence \"%s\" is linked to table \"%s\".",
16350  get_rel_name(tableId))));
16351  }
16352 
16353  /* Get and lock schema OID and check its permissions. */
16354  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
16355  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
16356 
16357  /* common checks on switching namespaces */
16358  CheckSetNamespace(oldNspOid, nspOid);
16359 
16360  objsMoved = new_object_addresses();
16361  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
16362  free_object_addresses(objsMoved);
16363 
16364  ObjectAddressSet(myself, RelationRelationId, relid);
16365 
16366  if (oldschema)
16367  *oldschema = oldNspOid;
16368 
16369  /* close rel, but keep lock until commit */
16370  relation_close(rel, NoLock);
16371 
16372  return myself;
16373 }
signed int int32
Definition: c.h:478
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2532
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2821
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int errdetail(const char *fmt,...)
Definition: elog.c:1202
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1910
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:424
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:537
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3010
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:827
#define RelationGetRelationName(relation)
Definition: rel.h:535
#define RelationGetNamespace(relation)
Definition: rel.h:542
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
char * relname
Definition: primnodes.h:74
Form_pg_class rd_rel
Definition: rel.h:110
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16381

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(), AlterObjectSchemaStmt::newschema, NoLock, NOTICE, ObjectAddressSet, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelidExtended(), RelationData::rd_rel, AlterObjectSchemaStmt::relation, relation_close(), relation_open(), RelationGetNamespace, RelationGetRelationName, RangeVar::relname, RVR_MISSING_OK, and sequenceIsOwned().

Referenced by ExecAlterObjectSchemaStmt().

◆ AlterTableNamespaceInternal()

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

Definition at line 16381 of file tablecmds.c.

16383 {
16384  Relation classRel;
16385 
16386  Assert(objsMoved != NULL);
16387 
16388  /* OK, modify the pg_class row and pg_depend entry */
16389  classRel = table_open(RelationRelationId, RowExclusiveLock);
16390 
16391  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
16392  nspOid, true, objsMoved);
16393 
16394  /* Fix the table's row type too, if it has one */
16395  if (OidIsValid(rel->rd_rel->reltype))
16396  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
16397  nspOid, false, false, objsMoved);
16398 
16399  /* Fix other dependent stuff */
16400  if (rel->rd_rel->relkind == RELKIND_RELATION ||
16401  rel->rd_rel->relkind == RELKIND_MATVIEW ||
16402  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16403  {
16404  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
16405  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
16406  objsMoved, AccessExclusiveLock);
16407  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
16408  false, objsMoved);
16409  }
16410 
16411  table_close(classRel, RowExclusiveLock);
16412 }
#define RowExclusiveLock
Definition: lockdefs.h:38
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
#define RelationGetRelid(relation)
Definition: rel.h:501
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16420
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:16535
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16490
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3952

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().

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 16810 of file tablecmds.c.

16812 {
16813  ListCell *cur_item;
16814 
16815  foreach(cur_item, on_commits)
16816  {
16817  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16818 
16819  if (!isCommit && oc->creating_subid == mySubid)
16820  {
16821  /* cur_item must be removed */
16823  pfree(oc);
16824  }
16825  else
16826  {
16827  /* cur_item must be preserved */
16828  if (oc->creating_subid == mySubid)
16829  oc->creating_subid = parentSubid;
16830  if (oc->deleting_subid == mySubid)
16831  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
16832  }
16833  }
16834 }
#define InvalidSubTransactionId
Definition: c.h:642
void pfree(void *pointer)
Definition: mcxt.c:1436
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:390
SubTransactionId creating_subid
Definition: tablecmds.c:122
SubTransactionId deleting_subid
Definition: tablecmds.c:123
static List * on_commits
Definition: tablecmds.c:126

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 16778 of file tablecmds.c.

16779 {
16780  ListCell *cur_item;
16781 
16782  foreach(cur_item, on_commits)
16783  {
16784  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16785 
16786  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
16788  {
16789  /* cur_item must be removed */
16791  pfree(oc);
16792  }
16793  else
16794  {
16795  /* cur_item must be preserved */
16798  }
16799  }
16800 }

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

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

◆ ATExecChangeOwner()

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

Definition at line 13686 of file tablecmds.c.

13687 {
13688  Relation target_rel;
13689  Relation class_rel;
13690  HeapTuple tuple;
13691  Form_pg_class tuple_class;
13692 
13693  /*
13694  * Get exclusive lock till end of transaction on the target table. Use
13695  * relation_open so that we can work on indexes and sequences.
13696  */
13697  target_rel = relation_open(relationOid, lockmode);
13698 
13699  /* Get its pg_class tuple, too */
13700  class_rel = table_open(RelationRelationId, RowExclusiveLock);
13701 
13702  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
13703  if (!HeapTupleIsValid(tuple))
13704  elog(ERROR, "cache lookup failed for relation %u", relationOid);
13705  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
13706 
13707  /* Can we change the ownership of this tuple? */
13708  switch (tuple_class->relkind)
13709  {
13710  case RELKIND_RELATION:
13711  case RELKIND_VIEW:
13712  case RELKIND_MATVIEW:
13713  case RELKIND_FOREIGN_TABLE:
13714  case RELKIND_PARTITIONED_TABLE:
13715  /* ok to change owner */
13716  break;
13717  case RELKIND_INDEX:
13718  if (!recursing)
13719  {
13720  /*
13721  * Because ALTER INDEX OWNER used to be allowed, and in fact
13722  * is generated by old versions of pg_dump, we give a warning
13723  * and do nothing rather than erroring out. Also, to avoid
13724  * unnecessary chatter while restoring those old dumps, say
13725  * nothing at all if the command would be a no-op anyway.
13726  */
13727  if (tuple_class->relowner != newOwnerId)
13728  ereport(WARNING,
13729  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13730  errmsg("cannot change owner of index \"%s\"",
13731  NameStr(tuple_class->relname)),
13732  errhint("Change the ownership of the index's table, instead.")));
13733  /* quick hack to exit via the no-op path */
13734  newOwnerId = tuple_class->relowner;
13735  }
13736  break;
13737  case RELKIND_PARTITIONED_INDEX:
13738  if (recursing)
13739  break;
13740  ereport(ERROR,
13741  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13742  errmsg("cannot change owner of index \"%s\"",
13743  NameStr(tuple_class->relname)),
13744  errhint("Change the ownership of the index's table, instead.")));
13745  break;
13746  case RELKIND_SEQUENCE:
13747  if (!recursing &&
13748  tuple_class->relowner != newOwnerId)
13749  {
13750  /* if it's an owned sequence, disallow changing it by itself */
13751  Oid tableId;
13752  int32 colId;
13753 
13754  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
13755  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
13756  ereport(ERROR,
13757  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13758  errmsg("cannot change owner of sequence \"%s\"",
13759  NameStr(tuple_class->relname)),
13760  errdetail("Sequence \"%s\" is linked to table \"%s\".",
13761  NameStr(tuple_class->relname),
13762  get_rel_name(tableId))));
13763  }
13764  break;
13765  case RELKIND_COMPOSITE_TYPE:
13766  if (recursing)
13767  break;
13768  ereport(ERROR,
13769  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13770  errmsg("\"%s\" is a composite type",
13771  NameStr(tuple_class->relname)),
13772  errhint("Use ALTER TYPE instead.")));
13773  break;
13774  case RELKIND_TOASTVALUE:
13775  if (recursing)
13776  break;
13777  /* FALL THRU */
13778  default:
13779  ereport(ERROR,
13780  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13781  errmsg("cannot change owner of relation \"%s\"",
13782  NameStr(tuple_class->relname)),
13783  errdetail_relkind_not_supported(tuple_class->relkind)));
13784  }
13785 
13786  /*
13787  * If the new owner is the same as the existing owner, consider the
13788  * command to have succeeded. This is for dump restoration purposes.
13789  */
13790  if (tuple_class->relowner != newOwnerId)
13791  {
13792  Datum repl_val[Natts_pg_class];
13793  bool repl_null[Natts_pg_class];
13794  bool repl_repl[Natts_pg_class];
13795  Acl *newAcl;
13796  Datum aclDatum;
13797  bool isNull;
13798  HeapTuple newtuple;
13799 
13800  /* skip permission checks when recursing to index or toast table */
13801  if (!recursing)
13802  {
13803  /* Superusers can always do it */
13804  if (!superuser())
13805  {
13806  Oid namespaceOid = tuple_class->relnamespace;
13807  AclResult aclresult;
13808 
13809  /* Otherwise, must be owner of the existing object */
13810  if (!object_ownercheck(RelationRelationId, relationOid, GetUserId()))
13812  RelationGetRelationName(target_rel));
13813 
13814  /* Must be able to become new owner */
13815  check_can_set_role(GetUserId(), newOwnerId);
13816 
13817  /* New owner must have CREATE privilege on namespace */
13818  aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId,
13819  ACL_CREATE);
13820  if (aclresult != ACLCHECK_OK)
13821  aclcheck_error(aclresult, OBJECT_SCHEMA,
13822  get_namespace_name(namespaceOid));
13823  }
13824  }
13825 
13826  memset(repl_null, false, sizeof(repl_null));
13827  memset(repl_repl, false, sizeof(repl_repl));
13828 
13829  repl_repl[Anum_pg_class_relowner - 1] = true;
13830  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
13831 
13832  /*
13833  * Determine the modified ACL for the new owner. This is only
13834  * necessary when the ACL is non-null.
13835  */
13836  aclDatum = SysCacheGetAttr(RELOID, tuple,
13837  Anum_pg_class_relacl,
13838  &isNull);
13839  if (!isNull)
13840  {
13841  newAcl = aclnewowner(DatumGetAclP(aclDatum),
13842  tuple_class->relowner, newOwnerId);
13843  repl_repl[Anum_pg_class_relacl - 1] = true;
13844  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
13845  }
13846 
13847  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
13848 
13849  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
13850 
13851  heap_freetuple(newtuple);
13852 
13853  /*
13854  * We must similarly update any per-column ACLs to reflect the new
13855  * owner; for neatness reasons that's split out as a subroutine.
13856  */
13857  change_owner_fix_column_acls(relationOid,
13858  tuple_class->relowner,
13859  newOwnerId);
13860 
13861  /*
13862  * Update owner dependency reference, if any. A composite type has
13863  * none, because it's tracked for the pg_type entry instead of here;
13864  * indexes and TOAST tables don't have their own entries either.
13865  */
13866  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
13867  tuple_class->relkind != RELKIND_INDEX &&
13868  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
13869  tuple_class->relkind != RELKIND_TOASTVALUE)
13870  changeDependencyOnOwner(RelationRelationId, relationOid,
13871  newOwnerId);
13872 
13873  /*
13874  * Also change the ownership of the table's row type, if it has one
13875  */
13876  if (OidIsValid(tuple_class->reltype))
13877  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
13878 
13879  /*
13880  * If we are operating on a table or materialized view, also change
13881  * the ownership of any indexes and sequences that belong to the
13882  * relation, as well as its toast table (if it has one).
13883  */
13884  if (tuple_class->relkind == RELKIND_RELATION ||
13885  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
13886  tuple_class->relkind == RELKIND_MATVIEW ||
13887  tuple_class->relkind == RELKIND_TOASTVALUE)
13888  {
13889  List *index_oid_list;
13890  ListCell *i;
13891 
13892  /* Find all the indexes belonging to this relation */
13893  index_oid_list = RelationGetIndexList(target_rel);
13894 
13895  /* For each index, recursively change its ownership */
13896  foreach(i, index_oid_list)
13897  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
13898 
13899  list_free(index_oid_list);
13900  }
13901 
13902  /* If it has a toast table, recurse to change its ownership */
13903  if (tuple_class->reltoastrelid != InvalidOid)
13904  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
13905  true, lockmode);
13906 
13907  /* If it has dependent sequences, recurse to change them too */
13908  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
13909  }
13910 
13911  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
13912 
13913  ReleaseSysCache(tuple);
13914  table_close(class_rel, RowExclusiveLock);
13915  relation_close(target_rel, NoLock);
13916 }
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1090
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5026
#define DatumGetAclP(X)
Definition: acl.h:120
int errhint(const char *fmt,...)
Definition: elog.c:1316
#define WARNING
Definition: elog.h:36
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
int i
Definition: isn.c:73
void list_free(List *list)
Definition: list.c:1545
@ OBJECT_SCHEMA
Definition: parsenodes.h:2005
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:313
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
#define RelationGetDescr(relation)
Definition: rel.h:527
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4738
bool superuser(void)
Definition: superuser.c:46
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:865
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:817
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1078
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:13686
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:13990
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:13925
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3822

References ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, aclnewowner(), AlterTypeOwnerInternal(), CatalogTupleUpdate(), change_owner_fix_column_acls(), change_owner_recurse_to_sequences(), changeDependencyOnOwner(), check_can_set_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_aclcheck(), object_ownercheck(), OBJECT_SCHEMA, ObjectIdGetDatum(), OidIsValid, 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(), ATExecCmd(), change_owner_recurse_to_sequences(), and shdepReassignOwned().

◆ check_of_type()

void check_of_type ( HeapTuple  typetuple)

Definition at line 6591 of file tablecmds.c.

6592 {
6593  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
6594  bool typeOk = false;
6595 
6596  if (typ->typtype == TYPTYPE_COMPOSITE)
6597  {
6598  Relation typeRelation;
6599 
6600  Assert(OidIsValid(typ->typrelid));
6601  typeRelation = relation_open(typ->typrelid, AccessShareLock);
6602  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6603 
6604  /*
6605  * Close the parent rel, but keep our AccessShareLock on it until xact
6606  * commit. That will prevent someone else from deleting or ALTERing
6607  * the type before the typed table creation/conversion commits.
6608  */
6609  relation_close(typeRelation, NoLock);
6610  }
6611  if (!typeOk)
6612  ereport(ERROR,
6613  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6614  errmsg("type %s is not a composite type",
6615  format_type_be(typ->oid))));
6616 }
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261

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().

◆ CheckRelationTableSpaceMove()

bool CheckRelationTableSpaceMove ( Relation  rel,
Oid  newTableSpaceId 
)

Definition at line 3304 of file tablecmds.c.

3305 {
3306  Oid oldTableSpaceId;
3307 
3308  /*
3309  * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3310  * stored as 0.
3311  */
3312  oldTableSpaceId = rel->rd_rel->reltablespace;
3313  if (newTableSpaceId == oldTableSpaceId ||
3314  (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3315  return false;
3316 
3317  /*
3318  * We cannot support moving mapped relations into different tablespaces.
3319  * (In particular this eliminates all shared catalogs.)
3320  */
3321  if (RelationIsMapped(rel))
3322  ereport(ERROR,
3323  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3324  errmsg("cannot move system relation \"%s\"",
3325  RelationGetRelationName(rel))));
3326 
3327  /* Cannot move a non-shared relation into pg_global */
3328  if (newTableSpaceId == GLOBALTABLESPACE_OID)
3329  ereport(ERROR,
3330  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3331  errmsg("only shared relations can be placed in pg_global tablespace")));
3332 
3333  /*
3334  * Do not allow moving temp tables of other backends ... their local
3335  * buffer manager is not going to cope.
3336  */
3337  if (RELATION_IS_OTHER_TEMP(rel))
3338  ereport(ERROR,
3339  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3340  errmsg("cannot move temporary tables of other sessions")));
3341 
3342  return true;
3343 }
#define RelationIsMapped(relation)
Definition: rel.h:550
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:656

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

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

◆ CheckTableNotInUse()

void CheckTableNotInUse ( Relation  rel,
const char *  stmt 
)

Definition at line 4018 of file tablecmds.c.

4019 {
4020  int expected_refcnt;
4021 
4022  expected_refcnt = rel->rd_isnailed ? 2 : 1;
4023  if (rel->rd_refcnt != expected_refcnt)
4024  ereport(ERROR,
4025  (errcode(ERRCODE_OBJECT_IN_USE),
4026  /* translator: first %s is a SQL command, eg ALTER TABLE */
4027  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
4028  stmt, RelationGetRelationName(rel))));
4029 
4030  if (rel->rd_rel->relkind != RELKIND_INDEX &&
4031  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
4033  ereport(ERROR,
4034  (errcode(ERRCODE_OBJECT_IN_USE),
4035  /* translator: first %s is a SQL command, eg ALTER TABLE */
4036  errmsg("cannot %s \"%s\" because it has pending trigger events",
4037  stmt, RelationGetRelationName(rel))));
4038 }
int rd_refcnt
Definition: rel.h:58
bool rd_isnailed
Definition: rel.h:61
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5910

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().

◆ DefineRelation()

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

Definition at line 662 of file tablecmds.c.

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

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(), GetAttributeStorage(), 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_aclcheck(), 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, 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, ColumnDef::storage_name, StoreCatalogInheritance(), StorePartitionBound(), StorePartitionKey(), PartitionSpec::strategy, 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().

◆ ExecuteTruncate()

void ExecuteTruncate ( TruncateStmt stmt)

Definition at line 1665 of file tablecmds.c.

1666 {
1667  List *rels = NIL;
1668  List *relids = NIL;
1669  List *relids_logged = NIL;
1670  ListCell *cell;
1671 
1672  /*
1673  * Open, exclusive-lock, and check all the explicitly-specified relations
1674  */
1675  foreach(cell, stmt->relations)
1676  {
1677  RangeVar *rv = lfirst(cell);
1678  Relation rel;
1679  bool recurse = rv->inh;
1680  Oid myrelid;
1681  LOCKMODE lockmode = AccessExclusiveLock;
1682 
1683  myrelid = RangeVarGetRelidExtended(rv, lockmode,
1685  NULL);
1686 
1687  /* don't throw error for "TRUNCATE foo, foo" */
1688  if (list_member_oid(relids, myrelid))
1689  continue;
1690 
1691  /* open the relation, we already hold a lock on it */
1692  rel = table_open(myrelid, NoLock);
1693 
1694  /*
1695  * RangeVarGetRelidExtended() has done most checks with its callback,
1696  * but other checks with the now-opened Relation remain.
1697  */
1699 
1700  rels = lappend(rels, rel);
1701  relids = lappend_oid(relids, myrelid);
1702 
1703  /* Log this relation only if needed for logical decoding */
1704  if (RelationIsLogicallyLogged(rel))
1705  relids_logged = lappend_oid(relids_logged, myrelid);
1706 
1707  if (recurse)
1708  {
1709  ListCell *child;
1710  List *children;
1711 
1712  children = find_all_inheritors(myrelid, lockmode, NULL);
1713 
1714  foreach(child, children)
1715  {
1716  Oid childrelid = lfirst_oid(child);
1717 
1718  if (list_member_oid(relids, childrelid))
1719  continue;
1720 
1721  /* find_all_inheritors already got lock */
1722  rel = table_open(childrelid, NoLock);
1723 
1724  /*
1725  * It is possible that the parent table has children that are
1726  * temp tables of other backends. We cannot safely access
1727  * such tables (because of buffering issues), and the best
1728  * thing to do is to silently ignore them. Note that this
1729  * check is the same as one of the checks done in
1730  * truncate_check_activity() called below, still it is kept
1731  * here for simplicity.
1732  */
1733  if (RELATION_IS_OTHER_TEMP(rel))
1734  {
1735  table_close(rel, lockmode);
1736  continue;
1737  }
1738 
1739  /*
1740  * Inherited TRUNCATE commands perform access permission
1741  * checks on the parent table only. So we skip checking the
1742  * children's permissions and don't call
1743  * truncate_check_perms() here.
1744  */
1747 
1748  rels = lappend(rels, rel);
1749  relids = lappend_oid(relids, childrelid);
1750 
1751  /* Log this relation only if needed for logical decoding */
1752  if (RelationIsLogicallyLogged(rel))
1753  relids_logged = lappend_oid(relids_logged, childrelid);
1754  }
1755  }
1756  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1757  ereport(ERROR,
1758  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1759  errmsg("cannot truncate only a partitioned table"),
1760  errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1761  }
1762 
1763  ExecuteTruncateGuts(rels, relids, relids_logged,
1764  stmt->behavior, stmt->restart_seqs);
1765 
1766  /* And close the rels */
1767  foreach(cell, rels)
1768  {
1769  Relation rel = (Relation) lfirst(cell);
1770 
1771  table_close(rel, NoLock);
1772  }
1773 }
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:256
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:699
struct RelationData * Relation
Definition: relcache.h:27
List * relations
Definition: parsenodes.h:2963
DropBehavior behavior
Definition: parsenodes.h:2965
bool restart_seqs
Definition: parsenodes.h:2964
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2230
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2164
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs)
Definition: tablecmds.c:1789
static void RangeVarCallbackForTruncate(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:16905

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().

◆ ExecuteTruncateGuts()

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

Definition at line 1789 of file tablecmds.c.

1793 {
1794  List *rels;
1795  List *seq_relids = NIL;
1796  HTAB *ft_htab = NULL;
1797  EState *estate;
1798  ResultRelInfo *resultRelInfos;
1799  ResultRelInfo *resultRelInfo;
1800  SubTransactionId mySubid;
1801  ListCell *cell;
1802  Oid *logrelids;
1803 
1804  /*
1805  * Check the explicitly-specified relations.
1806  *
1807  * In CASCADE mode, suck in all referencing relations as well. This
1808  * requires multiple iterations to find indirectly-dependent relations. At
1809  * each phase, we need to exclusive-lock new rels before looking for their
1810  * dependencies, else we might miss something. Also, we check each rel as
1811  * soon as we open it, to avoid a faux pas such as holding lock for a long
1812  * time on a rel we have no permissions for.
1813  */
1814  rels = list_copy(explicit_rels);
1815  if (behavior == DROP_CASCADE)
1816  {
1817  for (;;)
1818  {
1819  List *newrelids;
1820 
1821  newrelids = heap_truncate_find_FKs(relids);
1822  if (newrelids == NIL)
1823  break; /* nothing else to add */
1824 
1825  foreach(cell, newrelids)
1826  {
1827  Oid relid = lfirst_oid(cell);
1828  Relation rel;
1829 
1830  rel = table_open(relid, AccessExclusiveLock);
1831  ereport(NOTICE,
1832  (errmsg("truncate cascades to table \"%s\"",
1833  RelationGetRelationName(rel))));
1834  truncate_check_rel(relid, rel->rd_rel);
1835  truncate_check_perms(relid, rel->rd_rel);
1837  rels = lappend(rels, rel);
1838  relids = lappend_oid(relids, relid);
1839 
1840  /* Log this relation only if needed for logical decoding */
1841  if (RelationIsLogicallyLogged(rel))
1842  relids_logged = lappend_oid(relids_logged, relid);
1843  }
1844  }
1845  }
1846 
1847  /*
1848  * Check foreign key references. In CASCADE mode, this should be
1849  * unnecessary since we just pulled in all the references; but as a
1850  * cross-check, do it anyway if in an Assert-enabled build.
1851  */
1852 #ifdef USE_ASSERT_CHECKING
1853  heap_truncate_check_FKs(rels, false);
1854 #else
1855  if (behavior == DROP_RESTRICT)
1856  heap_truncate_check_FKs(rels, false);
1857 #endif
1858 
1859  /*
1860  * If we are asked to restart sequences, find all the sequences, lock them
1861  * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1862  * We want to do this early since it's pointless to do all the truncation
1863  * work only to fail on sequence permissions.
1864  */
1865  if (restart_seqs)
1866  {
1867  foreach(cell, rels)
1868  {
1869  Relation rel = (Relation) lfirst(cell);
1870  List *seqlist = getOwnedSequences(RelationGetRelid(rel));
1871  ListCell *seqcell;
1872 
1873  foreach(seqcell, seqlist)
1874  {
1875  Oid seq_relid = lfirst_oid(seqcell);
1876  Relation seq_rel;
1877 
1878  seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1879 
1880  /* This check must match AlterSequence! */
1881  if (!object_ownercheck(RelationRelationId, seq_relid, GetUserId()))
1883  RelationGetRelationName(seq_rel));
1884 
1885  seq_relids = lappend_oid(seq_relids, seq_relid);
1886 
1887  relation_close(seq_rel, NoLock);
1888  }
1889  }
1890  }
1891 
1892  /* Prepare to catch AFTER triggers. */
1894 
1895  /*
1896  * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1897  * each relation. We don't need to call ExecOpenIndices, though.
1898  *
1899  * We put the ResultRelInfos in the es_opened_result_relations list, even
1900  * though we don't have a range table and don't populate the
1901  * es_result_relations array. That's a bit bogus, but it's enough to make
1902  * ExecGetTriggerResultRel() find them.
1903  */
1904  estate = CreateExecutorState();
1905  resultRelInfos = (ResultRelInfo *)
1906  palloc(list_length(rels) * sizeof(ResultRelInfo));
1907  resultRelInfo = resultRelInfos;
1908  foreach(cell, rels)
1909  {
1910  Relation rel = (Relation) lfirst(cell);
1911 
1912  InitResultRelInfo(resultRelInfo,
1913  rel,
1914  0, /* dummy rangetable index */
1915  NULL,
1916  0);
1917  estate->es_opened_result_relations =
1918  lappend(estate->es_opened_result_relations, resultRelInfo);
1919  resultRelInfo++;
1920  }
1921 
1922  /*
1923  * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
1924  * truncating (this is because one of them might throw an error). Also, if
1925  * we were to allow them to prevent statement execution, that would need
1926  * to be handled here.
1927  */
1928  resultRelInfo = resultRelInfos;
1929  foreach(cell, rels)
1930  {
1931  ExecBSTruncateTriggers(estate, resultRelInfo);
1932  resultRelInfo++;
1933  }
1934 
1935  /*
1936  * OK, truncate each table.
1937  */
1938  mySubid = GetCurrentSubTransactionId();
1939 
1940  foreach(cell, rels)
1941  {
1942  Relation rel = (Relation) lfirst(cell);
1943 
1944  /* Skip partitioned tables as there is nothing to do */
1945  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1946  continue;
1947 
1948  /*
1949  * Build the lists of foreign tables belonging to each foreign server
1950  * and pass each list to the foreign data wrapper's callback function,
1951  * so that each server can truncate its all foreign tables in bulk.
1952  * Each list is saved as a single entry in a hash table that uses the
1953  * server OID as lookup key.
1954  */
1955  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1956  {
1958  bool found;
1959  ForeignTruncateInfo *ft_info;
1960 
1961  /* First time through, initialize hashtable for foreign tables */
1962  if (!ft_htab)
1963  {
1964  HASHCTL hctl;
1965 
1966  memset(&hctl, 0, sizeof(HASHCTL));
1967  hctl.keysize = sizeof(Oid);
1968  hctl.entrysize = sizeof(ForeignTruncateInfo);
1969  hctl.hcxt = CurrentMemoryContext;
1970 
1971  ft_htab = hash_create("TRUNCATE for Foreign Tables",
1972  32, /* start small and extend */
1973  &hctl,
1975  }
1976 
1977  /* Find or create cached entry for the foreign table */
1978  ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
1979  if (!found)
1980  {
1981  ft_info->serverid = serverid;
1982  ft_info->rels = NIL;
1983  }
1984 
1985  /*
1986  * Save the foreign table in the entry of the server that the
1987  * foreign table belongs to.
1988  */
1989  ft_info->rels = lappend(ft_info->rels, rel);
1990  continue;
1991  }
1992 
1993  /*
1994  * Normally, we need a transaction-safe truncation here. However, if
1995  * the table was either created in the current (sub)transaction or has
1996  * a new relfilenumber in the current (sub)transaction, then we can
1997  * just truncate it in-place, because a rollback would cause the whole
1998  * table or the current physical file to be thrown away anyway.
1999  */
2000  if (rel->rd_createSubid == mySubid ||
2001  rel->rd_newRelfilelocatorSubid == mySubid)
2002  {
2003  /* Immediate, non-rollbackable truncation is OK */
2004  heap_truncate_one_rel(rel);
2005  }
2006  else
2007  {
2008  Oid heap_relid;
2009  Oid toast_relid;
2010  ReindexParams reindex_params = {0};
2011 
2012  /*
2013  * This effectively deletes all rows in the table, and may be done
2014  * in a serializable transaction. In that case we must record a
2015  * rw-conflict in to this transaction from each transaction
2016  * holding a predicate lock on the table.
2017  */
2019 
2020  /*
2021  * Need the full transaction-safe pushups.
2022  *
2023  * Create a new empty storage file for the relation, and assign it
2024  * as the relfilenumber value. The old storage file is scheduled
2025  * for deletion at commit.
2026  */
2027  RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
2028 
2029  heap_relid = RelationGetRelid(rel);
2030 
2031  /*
2032  * The same for the toast table, if any.
2033  */
2034  toast_relid = rel->rd_rel->reltoastrelid;
2035  if (OidIsValid(toast_relid))
2036  {
2037  Relation toastrel = relation_open(toast_relid,
2039 
2040  RelationSetNewRelfilenumber(toastrel,
2041  toastrel->rd_rel->relpersistence);
2042  table_close(toastrel, NoLock);
2043  }
2044 
2045  /*
2046  * Reconstruct the indexes to match, and we're done.
2047  */
2049  &reindex_params);
2050  }
2051 
2052  pgstat_count_truncate(rel);
2053  }
2054 
2055  /* Now go through the hash table, and truncate foreign tables */
2056  if (ft_htab)
2057  {
2058  ForeignTruncateInfo *ft_info;
2059  HASH_SEQ_STATUS seq;
2060 
2061  hash_seq_init(&seq, ft_htab);
2062 
2063  PG_TRY();
2064  {
2065  while ((ft_info = hash_seq_search(&seq)) != NULL)
2066  {
2067  FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2068 
2069  /* truncate_check_rel() has checked that already */
2070  Assert(routine->ExecForeignTruncate != NULL);
2071 
2072  routine->ExecForeignTruncate(ft_info->rels,
2073  behavior,
2074  restart_seqs);
2075  }
2076  }
2077  PG_FINALLY();
2078  {
2079  hash_destroy(ft_htab);
2080  }
2081  PG_END_TRY();
2082  }
2083 
2084  /*
2085  * Restart owned sequences if we were asked to.
2086  */
2087  foreach(cell, seq_relids)
2088  {
2089  Oid seq_relid = lfirst_oid(cell);
2090 
2091  ResetSequence(seq_relid);
2092  }
2093 
2094  /*
2095  * Write a WAL record to allow this set of actions to be logically
2096  * decoded.
2097  *
2098  * Assemble an array of relids so we can write a single WAL record for the
2099  * whole action.
2100  */
2101  if (relids_logged != NIL)
2102  {
2103  xl_heap_truncate xlrec;
2104  int i = 0;
2105 
2106  /* should only get here if wal_level >= logical */
2108 
2109  logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
2110  foreach(cell, relids_logged)
2111  logrelids[i++] = lfirst_oid(cell);
2112 
2113  xlrec.dbId = MyDatabaseId;
2114  xlrec.nrelids = list_length(relids_logged);
2115  xlrec.flags = 0;
2116  if (behavior == DROP_CASCADE)
2117  xlrec.flags |= XLH_TRUNCATE_CASCADE;
2118  if (restart_seqs)
2120 
2121  XLogBeginInsert();
2122  XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
2123  XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
2124 
2126 
2127  (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
2128  }
2129 
2130  /*
2131  * Process all AFTER STATEMENT TRUNCATE triggers.
2132  */
2133  resultRelInfo = resultRelInfos;
2134  foreach(cell, rels)
2135  {
2136  ExecASTruncateTriggers(estate, resultRelInfo);
2137  resultRelInfo++;
2138  }
2139 
2140  /* Handle queued AFTER triggers */
2141  AfterTriggerEndQuery(estate);
2142 
2143  /* We can clean up the EState now */
2144  FreeExecutorState(estate);
2145 
2146  /*
2147  * Close any rels opened by CASCADE (can't do this while EState still
2148  * holds refs)
2149  */
2150  rels = list_difference_ptr(rels, explicit_rels);
2151  foreach(cell, rels)
2152  {
2153  Relation rel = (Relation) lfirst(cell);
2154 
2155  table_close(rel, NoLock);
2156  }
2157 }
uint32 SubTransactionId
Definition: c.h:640
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:863
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:350
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1431
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1421
#define PG_TRY(...)
Definition: elog.h:370
#define PG_END_TRY(...)
Definition: elog.h:395
#define PG_FINALLY(...)
Definition: elog.h:387
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition: execMain.c:1189
EState * CreateExecutorState(void)
Definition: execUtils.c:93
void FreeExecutorState(EState *estate)
Definition: execUtils.c:193
struct ResultRelInfo ResultRelInfo
Oid GetForeignServerIdByRelId(Oid relid)
Definition: foreign.c:342
FdwRoutine * GetFdwRoutineByServerId(Oid serverid)
Definition: foreign.c:364
Oid MyDatabaseId
Definition: globals.c:89
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3181
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3086
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3042
#define XLOG_HEAP_TRUNCATE
Definition: heapam_xlog.h:35
#define XLH_TRUNCATE_RESTART_SEQS
Definition: heapam_xlog.h:121
#define SizeOfHeapTruncate
Definition: heapam_xlog.h:136
#define XLH_TRUNCATE_CASCADE
Definition: heapam_xlog.h:120
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
bool reindex_relation(Oid relid, int flags, ReindexParams *params)
Definition: index.c:3860
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:155
List * list_difference_ptr(const List *list1, const List *list2)
Definition: list.c:1262
List * list_copy(const List *oldlist)
Definition: list.c:1572
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
@ DROP_CASCADE
Definition: parsenodes.h:2043
@ DROP_RESTRICT
Definition: parsenodes.h:2042
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2006
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:935
void pgstat_count_truncate(Relation rel)
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4325
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition: relcache.c:3708
void ResetSequence(Oid seq_relid)
Definition: sequence.c:274
List * es_opened_result_relations
Definition: execnodes.h:634
ExecForeignTruncate_function ExecForeignTruncate
Definition: fdwapi.h:263
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
MemoryContext hcxt
Definition: hsearch.h:86
Definition: dynahash.c:220
SubTransactionId rd_newRelfilelocatorSubid
Definition: rel.h:103
SubTransactionId rd_createSubid
Definition: rel.h:102
struct ForeignTruncateInfo ForeignTruncateInfo
static void truncate_check_perms(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2212
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3204
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3251
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:4974
void AfterTriggerBeginQuery(void)
Definition: trigger.c:4954
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:780
#define XLogLogicalInfoActive()
Definition: xlog.h:121
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:149
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:351
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:451
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:433
void XLogBeginInsert(void)
Definition: xloginsert.c:150

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_ownercheck(), OBJECT_SEQUENCE, OidIsValid, palloc(), PG_END_TRY, PG_FINALLY, PG_TRY, pgstat_count_truncate(), RelationData::rd_createSubid, RelationData::rd_newRelfilelocatorSubid, RelationData::rd_rel, REINDEX_REL_PROCESS_TOAST, reindex_relation(), relation_close(), relation_open(), RelationGetRelationName, RelationGetRelid, RelationIsLogicallyLogged, RelationSetNewRelfilenumber(), 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().

◆ find_composite_type_dependencies()

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

Definition at line 6424 of file tablecmds.c.

6426 {
6427  Relation depRel;
6428  ScanKeyData key[2];
6429  SysScanDesc depScan;
6430  HeapTuple depTup;
6431 
6432  /* since this function recurses, it could be driven to stack overflow */
6434 
6435  /*
6436  * We scan pg_depend to find those things that depend on the given type.
6437  * (We assume we can ignore refobjsubid for a type.)
6438  */
6439  depRel = table_open(DependRelationId, AccessShareLock);
6440 
6441  ScanKeyInit(&key[0],
6442  Anum_pg_depend_refclassid,
6443  BTEqualStrategyNumber, F_OIDEQ,
6444  ObjectIdGetDatum(TypeRelationId));
6445  ScanKeyInit(&key[1],
6446  Anum_pg_depend_refobjid,
6447  BTEqualStrategyNumber, F_OIDEQ,
6448  ObjectIdGetDatum(typeOid));
6449 
6450  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6451  NULL, 2, key);
6452 
6453  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6454  {
6455  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6456  Relation rel;
6457  Form_pg_attribute att;
6458 
6459  /* Check for directly dependent types */
6460  if (pg_depend->classid == TypeRelationId)
6461  {
6462  /*
6463  * This must be an array, domain, or range containing the given
6464  * type, so recursively check for uses of this type. Note that
6465  * any error message will mention the original type not the
6466  * container; this is intentional.
6467  */
6468  find_composite_type_dependencies(pg_depend->objid,
6469  origRelation, origTypeName);
6470  continue;
6471  }
6472 
6473  /* Else, ignore dependees that aren't user columns of relations */
6474  /* (we assume system columns are never of interesting types) */
6475  if (pg_depend->classid != RelationRelationId ||
6476  pg_depend->objsubid <= 0)
6477  continue;
6478 
6479  rel = relation_open(pg_depend->objid, AccessShareLock);
6480  att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
6481 
6482  if (rel->rd_rel->relkind == RELKIND_RELATION ||
6483  rel->rd_rel->relkind == RELKIND_MATVIEW ||
6484  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6485  {
6486  if (origTypeName)
6487  ereport(ERROR,
6488  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6489  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6490  origTypeName,
6492  NameStr(att->attname))));
6493  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6494  ereport(ERROR,
6495  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6496  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6497  RelationGetRelationName(origRelation),
6499  NameStr(att->attname))));
6500  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
6501  ereport(ERROR,
6502  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6503  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
6504  RelationGetRelationName(origRelation),
6506  NameStr(att->attname))));
6507  else
6508  ereport(ERROR,
6509  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6510  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
6511  RelationGetRelationName(origRelation),
6513  NameStr(att->attname))));
6514  }
6515  else if (OidIsValid(rel->rd_rel->reltype))
6516  {
6517  /*
6518  * A view or composite type itself isn't a problem, but we must
6519  * recursively check for indirect dependencies via its rowtype.
6520  */
6522  origRelation, origTypeName);
6523  }
6524 
6526  }
6527 
6528  systable_endscan(depScan);
6529 
6531 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
void check_stack_depth(void)
Definition: postgres.c:3454
TupleDesc rd_att
Definition: rel.h:111
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:6424

References AccessShareLock, BTEqualStrategyNumber, check_stack_depth(), ereport, errcode(), errmsg(), ERROR, 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(), and get_rels_with_domain().

◆ has_partition_ancestor_privs()

bool has_partition_ancestor_privs ( Oid  relid,
Oid  userid,
AclMode  acl 
)

Definition at line 16880 of file tablecmds.c.

16881 {
16882  List *ancestors;
16883  ListCell *lc;
16884 
16885  if (!get_rel_relispartition(relid))
16886  return false;
16887 
16888  ancestors = get_partition_ancestors(relid);
16889  foreach(lc, ancestors)
16890  {
16891  Oid ancestor = lfirst_oid(lc);
16892 
16893  if (OidIsValid(ancestor) &&
16894  pg_class_aclcheck(ancestor, userid, acl) == ACLCHECK_OK)
16895  return true;
16896  }
16897 
16898  return false;
16899 }
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:3931
bool get_rel_relispartition(Oid relid)
Definition: lsyscache.c:2009
List * get_partition_ancestors(Oid relid)
Definition: partition.c:133

References ACLCHECK_OK, get_partition_ancestors(), get_rel_relispartition(), lfirst_oid, OidIsValid, and pg_class_aclcheck().

Referenced by cluster_is_permitted_for_relation(), LockTableAclCheck(), RangeVarCallbackForReindexIndex(), RangeVarCallbackMaintainsTable(), ReindexMultipleTables(), and vacuum_is_permitted_for_relation().

◆ PartConstraintImpliedByRelConstraint()

bool PartConstraintImpliedByRelConstraint ( Relation  scanrel,
List partConstraint 
)

Definition at line 17412 of file tablecmds.c.

17414 {
17415  List *existConstraint = NIL;
17416  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
17417  int i;
17418 
17419  if (constr && constr->has_not_null)
17420  {
17421  int natts = scanrel->rd_att->natts;
17422 
17423  for (i = 1; i <= natts; i++)
17424  {
17425  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
17426 
17427  if (att->attnotnull && !att->attisdropped)
17428  {
17429  NullTest *ntest = makeNode(NullTest);
17430 
17431  ntest->arg = (Expr *) makeVar(1,
17432  i,
17433  att->atttypid,
17434  att->atttypmod,
17435  att->attcollation,
17436  0);
17437  ntest->nulltesttype = IS_NOT_NULL;
17438 
17439  /*
17440  * argisrow=false is correct even for a composite column,
17441  * because attnotnull does not represent a SQL-spec IS NOT
17442  * NULL test in such a case, just IS DISTINCT FROM NULL.
17443  */
17444  ntest->argisrow = false;
17445  ntest->location = -1;
17446  existConstraint = lappend(existConstraint, ntest);
17447  }
17448  }
17449  }
17450 
17451  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
17452 }
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
@ IS_NOT_NULL
Definition: primnodes.h:1513
NullTestType nulltesttype
Definition: primnodes.h:1520
int location
Definition: primnodes.h:1523
Expr * arg
Definition: primnodes.h:1519
bool has_not_null
Definition: tupdesc.h:44
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:17465

References NullTest::arg, 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().

◆ PreCommit_on_commit_actions()

void PreCommit_on_commit_actions ( void  )

Definition at line 16679 of file tablecmds.c.

16680 {
16681  ListCell *l;
16682  List *oids_to_truncate = NIL;
16683  List *oids_to_drop = NIL;
16684 
16685  foreach(l, on_commits)
16686  {
16687  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
16688 
16689  /* Ignore entry if already dropped in this xact */
16691  continue;
16692 
16693  switch (oc->oncommit)
16694  {
16695  case ONCOMMIT_NOOP:
16697  /* Do nothing (there shouldn't be such entries, actually) */
16698  break;
16699  case ONCOMMIT_DELETE_ROWS:
16700 
16701  /*
16702  * If this transaction hasn't accessed any temporary
16703  * relations, we can skip truncating ON COMMIT DELETE ROWS
16704  * tables, as they must still be empty.
16705  */
16707  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
16708  break;
16709  case ONCOMMIT_DROP:
16710  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
16711  break;
16712  }
16713  }
16714 
16715  /*
16716  * Truncate relations before dropping so that all dependencies between
16717  * relations are removed after they are worked on. Doing it like this
16718  * might be a waste as it is possible that a relation being truncated will
16719  * be dropped anyway due to its parent being dropped, but this makes the
16720  * code more robust because of not having to re-check that the relation
16721  * exists at truncation time.
16722  */
16723  if (oids_to_truncate != NIL)
16724  heap_truncate(oids_to_truncate);
16725 
16726  if (oids_to_drop != NIL)
16727  {
16728  ObjectAddresses *targetObjects = new_object_addresses();
16729 
16730  foreach(l, oids_to_drop)
16731  {
16732  ObjectAddress object;
16733 
16734  object.classId = RelationRelationId;
16735  object.objectId = lfirst_oid(l);
16736  object.objectSubId = 0;
16737 
16738  Assert(!object_address_present(&object, targetObjects));
16739 
16740  add_exact_object_address(&object, targetObjects);
16741  }
16742 
16743  /*
16744  * Since this is an automatic drop, rather than one directly initiated
16745  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
16746  */
16747  performMultipleDeletions(targetObjects, DROP_CASCADE,
16749 
16750 #ifdef USE_ASSERT_CHECKING
16751 
16752  /*
16753  * Note that table deletion will call remove_on_commit_action, so the
16754  * entry should get marked as deleted.
16755  */
16756  foreach(l, on_commits)
16757  {
16758  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
16759 
16760  if (oc->oncommit != ONCOMMIT_DROP)
16761  continue;
16762 
16764  }
16765 #endif
16766  }
16767 }
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:387
#define PERFORM_DELETION_QUIETLY
Definition: dependency.h:138
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:136
void heap_truncate(List *relids)
Definition: heap.c:3001
@ ONCOMMIT_DELETE_ROWS
Definition: primnodes.h:51
@ ONCOMMIT_PRESERVE_ROWS
Definition: primnodes.h:50
@ ONCOMMIT_DROP
Definition: primnodes.h:52
OnCommitAction oncommit
Definition: tablecmds.c:113
int MyXactFlags
Definition: xact.c:136
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:102

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(), on_commits, 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().

◆ RangeVarCallbackMaintainsTable()

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

Definition at line 16845 of file tablecmds.c.

16847 {
16848  char relkind;
16849 
16850  /* Nothing to do if the relation was not found. */
16851  if (!OidIsValid(relId))
16852  return;
16853 
16854  /*
16855  * If the relation does exist, check whether it's an index. But note that
16856  * the relation might have been dropped between the time we did the name
16857  * lookup and now. In that case, there's nothing to do.
16858  */
16859  relkind = get_rel_relkind(relId);
16860  if (!relkind)
16861  return;
16862  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
16863  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
16864  ereport(ERROR,
16865  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16866  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
16867 
16868  /* Check permissions */
16872  relation->relname);
16873 }
#define ACL_MAINTAIN
Definition: parsenodes.h:97
bool has_partition_ancestor_privs(Oid relid, Oid userid, AclMode acl)
Definition: tablecmds.c:16880

References ACL_MAINTAIN, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, ereport, errcode(), errmsg(), ERROR, get_rel_relkind(), GetUserId(), has_partition_ancestor_privs(), OBJECT_TABLE, OidIsValid, pg_class_aclcheck(), and RangeVar::relname.

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

◆ RangeVarCallbackOwnsRelation()

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

Definition at line 16929 of file tablecmds.c.

16931 {
16932  HeapTuple tuple;
16933 
16934  /* Nothing to do if the relation was not found. */
16935  if (!OidIsValid(relId))
16936  return;
16937 
16938  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
16939  if (!HeapTupleIsValid(tuple)) /* should not happen */
16940  elog(ERROR, "cache lookup failed for relation %u", relId);
16941 
16942  if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
16944  relation->relname);
16945 
16946  if (!allowSystemTableMods &&
16947  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
16948  ereport(ERROR,
16949  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
16950  errmsg("permission denied: \"%s\" is a system catalog",
16951  relation->relname)));
16952 
16953  ReleaseSysCache(tuple);
16954 }
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:87

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

Referenced by AlterSequence(), and ProcessUtilitySlow().

◆ register_on_commit_action()

void register_on_commit_action ( Oid  relid,
OnCommitAction  action 
)

Definition at line 16620 of file tablecmds.c.

16621 {
16622  OnCommitItem *oc;
16623  MemoryContext oldcxt;
16624 
16625  /*
16626  * We needn't bother registering the relation unless there is an ON COMMIT
16627  * action we need to take.
16628  */
16630  return;
16631 
16633 
16634  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
16635  oc->relid = relid;
16636  oc->oncommit = action;
16639 
16640  /*
16641  * We use lcons() here so that ON COMMIT actions are processed in reverse
16642  * order of registration. That might not be essential but it seems
16643  * reasonable.
16644  */
16645  on_commits = lcons(oc, on_commits);
16646 
16647  MemoryContextSwitchTo(oldcxt);
16648 }
List * lcons(void *datum, List *list)
Definition: list.c:494
MemoryContext CacheMemoryContext
Definition: mcxt.c:144
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138

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

Referenced by heap_create_with_catalog().

◆ remove_on_commit_action()

void remove_on_commit_action ( Oid  relid)

Definition at line 16656 of file tablecmds.c.

16657 {
16658  ListCell *l;
16659 
16660  foreach(l, on_commits)
16661  {
16662  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
16663 
16664  if (oc->relid == relid)
16665  {
16667  break;
16668  }
16669  }
16670 }

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

Referenced by heap_drop_with_catalog().

◆ RemoveRelations()

void RemoveRelations ( DropStmt drop)

Definition at line 1342 of file tablecmds.c.

1343 {
1344  ObjectAddresses *objects;
1345  char relkind;
1346  ListCell *cell;
1347  int flags = 0;
1348  LOCKMODE lockmode = AccessExclusiveLock;
1349 
1350  /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1351  if (drop->concurrent)
1352  {
1353  /*
1354  * Note that for temporary relations this lock may get upgraded later
1355  * on, but as no other session can access a temporary relation, this
1356  * is actually fine.
1357  */
1358  lockmode = ShareUpdateExclusiveLock;
1359  Assert(drop->removeType == OBJECT_INDEX);
1360  if (list_length(drop->objects) != 1)
1361  ereport(ERROR,
1362  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1363  errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1364  if (drop->behavior == DROP_CASCADE)
1365  ereport(ERROR,
1366  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1367  errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1368  }
1369 
1370  /*
1371  * First we identify all the relations, then we delete them in a single
1372  * performMultipleDeletions() call. This is to avoid unwanted DROP
1373  * RESTRICT errors if one of the relations depends on another.
1374  */
1375 
1376  /* Determine required relkind */
1377  switch (drop->removeType)
1378  {
1379  case OBJECT_TABLE:
1380  relkind = RELKIND_RELATION;
1381  break;
1382 
1383  case OBJECT_INDEX:
1384  relkind = RELKIND_INDEX;
1385  break;
1386 
1387  case OBJECT_SEQUENCE:
1388  relkind = RELKIND_SEQUENCE;
1389  break;
1390 
1391  case OBJECT_VIEW:
1392  relkind = RELKIND_VIEW;
1393  break;
1394 
1395  case OBJECT_MATVIEW:
1396  relkind = RELKIND_MATVIEW;
1397  break;
1398 
1399  case OBJECT_FOREIGN_TABLE:
1400  relkind = RELKIND_FOREIGN_TABLE;
1401  break;
1402 
1403  default:
1404  elog(ERROR, "unrecognized drop object type: %d",
1405  (int) drop->removeType);
1406  relkind = 0; /* keep compiler quiet */
1407  break;
1408  }
1409 
1410  /* Lock and validate each relation; build a list of object addresses */
1411  objects = new_object_addresses();
1412 
1413  foreach(cell, drop->objects)
1414  {
1415  RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1416  Oid relOid;
1417  ObjectAddress obj;
1419 
1420  /*
1421  * These next few steps are a great deal like relation_openrv, but we
1422  * don't bother building a relcache entry since we don't need it.
1423  *
1424  * Check for shared-cache-inval messages before trying to access the
1425  * relation. This is needed to cover the case where the name
1426  * identifies a rel that has been dropped and recreated since the
1427  * start of our transaction: if we don't flush the old syscache entry,
1428  * then we'll latch onto that entry and suffer an error later.
1429  */
1431 
1432  /* Look up the appropriate relation using namespace search. */
1433  state.expected_relkind = relkind;
1434  state.heap_lockmode = drop->concurrent ?
1436  /* We must initialize these fields to show that no locks are held: */
1437  state.heapOid = InvalidOid;
1438  state.partParentOid = InvalidOid;
1439 
1440  relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1442  (void *) &state);
1443 
1444  /* Not there? */
1445  if (!OidIsValid(relOid))
1446  {
1447  DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1448  continue;
1449  }
1450 
1451  /*
1452  * Decide if concurrent mode needs to be used here or not. The
1453  * callback retrieved the rel's persistence for us.
1454  */
1455  if (drop->concurrent &&
1456  state.actual_relpersistence != RELPERSISTENCE_TEMP)
1457  {
1458  Assert(list_length(drop->objects) == 1 &&
1459  drop->removeType == OBJECT_INDEX);
1461  }
1462 
1463  /*
1464  * Concurrent index drop cannot be used with partitioned indexes,
1465  * either.
1466  */
1467  if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1468  state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1469  ereport(ERROR,
1470  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1471  errmsg("cannot drop partitioned index \"%s\" concurrently",
1472  rel->relname)));
1473 
1474  /*
1475  * If we're told to drop a partitioned index, we must acquire lock on
1476  * all the children of its parent partitioned table before proceeding.
1477  * Otherwise we'd try to lock the child index partitions before their
1478  * tables, leading to potential deadlock against other sessions that
1479  * will lock those objects in the other order.
1480  */
1481  if (state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1482  (void) find_all_inheritors(state.heapOid,
1483  state.heap_lockmode,
1484  NULL);
1485 
1486  /* OK, we're ready to delete this one */
1487  obj.classId = RelationRelationId;
1488  obj.objectId = relOid;
1489  obj.objectSubId = 0;
1490 
1491  add_exact_object_address(&obj, objects);
1492  }
1493 
1494  performMultipleDeletions(objects, drop->behavior, flags);
1495 
1496  free_object_addresses(objects);
1497 }
#define PERFORM_DELETION_CONCURRENTLY
Definition: dependency.h:137
void AcceptInvalidationMessages(void)
Definition: inval.c:746
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3105
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:1987
@ OBJECT_VIEW
Definition: parsenodes.h:2020
bool missing_ok
Definition: parsenodes.h:2952
List * objects
Definition: parsenodes.h:2949
ObjectType removeType
Definition: parsenodes.h:2950
bool concurrent
Definition: parsenodes.h:2953
DropBehavior behavior
Definition: parsenodes.h:2951
Definition: regguts.h:318
static void DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
Definition: tablecmds.c:1267
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:1506

References AcceptInvalidationMessages(), AccessExclusiveLock, add_exact_object_address(), Assert(), DropStmt::behavior, ObjectAddress::classId, DropStmt::concurrent, DROP_CASCADE, DropErrorMsgNonExistent(), elog(), ereport, errcode(), errmsg(), ERROR, find_all_inheritors(), free_object_addresses(), 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, PERFORM_DELETION_CONCURRENTLY, performMultipleDeletions(), RangeVarCallbackForDropRelation(), RangeVarGetRelidExtended(), RangeVar::relname, DropStmt::removeType, RVR_MISSING_OK, and ShareUpdateExclusiveLock.

Referenced by ExecDropStmt().

◆ renameatt()

ObjectAddress renameatt ( RenameStmt stmt)

Definition at line 3617 of file tablecmds.c.

3618 {
3619  Oid relid;
3621  ObjectAddress address;
3622 
3623  /* lock level taken here should match renameatt_internal */
3625  stmt->missing_ok ? RVR_MISSING_OK : 0,
3627  NULL);
3628 
3629  if (!OidIsValid(relid))
3630  {
3631  ereport(NOTICE,
3632  (errmsg("relation \"%s\" does not exist, skipping",
3633  stmt->relation->relname)));
3634  return InvalidObjectAddress;
3635  }
3636 
3637  attnum =
3638  renameatt_internal(relid,
3639  stmt->subname, /* old att name */
3640  stmt->newname, /* new att name */
3641  stmt->relation->inh, /* recursive? */
3642  false, /* recursing? */
3643  0, /* expected inhcount */
3644  stmt->behavior);
3645 
3646  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3647 
3648  return address;
3649 }
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
RangeVar * relation
Definition: parsenodes.h:3245
bool missing_ok
Definition: parsenodes.h:3251
DropBehavior behavior
Definition: parsenodes.h:3250
char * newname
Definition: parsenodes.h:3249
char * subname
Definition: parsenodes.h:3247
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:3452
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3597

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

Referenced by ExecRenameStmt().

◆ RenameConstraint()

ObjectAddress RenameConstraint ( RenameStmt stmt)

Definition at line 3761 of file tablecmds.c.

3762 {
3763  Oid relid = InvalidOid;
3764  Oid typid = InvalidOid;
3765 
3766  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3767  {
3768  Relation rel;
3769  HeapTuple tup;
3770 
3772  rel = table_open(TypeRelationId, RowExclusiveLock);
3773  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3774  if (!HeapTupleIsValid(tup))
3775  elog(ERROR, "cache lookup failed for type %u", typid);
3776  checkDomainOwner(tup);
3777  ReleaseSysCache(tup);
3778  table_close(rel, NoLock);
3779  }
3780  else
3781  {
3782  /* lock level taken here should match rename_constraint_internal */
3784  stmt->missing_ok ? RVR_MISSING_OK : 0,
3786  NULL);
3787  if (!OidIsValid(relid))
3788  {
3789  ereport(NOTICE,
3790  (errmsg("relation \"%s\" does not exist, skipping",
3791  stmt->relation->relname)));
3792  return InvalidObjectAddress;
3793  }
3794  }
3795 
3796  return
3797  rename_constraint_internal(relid, typid,
3798  stmt->subname,
3799  stmt->newname,
3800  (stmt->relation &&
3801  stmt->relation->inh), /* recursive? */
3802  false, /* recursing? */
3803  0 /* expected inhcount */ );
3804 }
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:458
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:1982
ObjectType renameType
Definition: parsenodes.h:3243
Node * object
Definition: parsenodes.h:3246
@ TYPEOID
Definition: syscache.h:114
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:3655
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3421

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(), RangeVar::relname, rename_constraint_internal(), RenameStmt::renameType, RowExclusiveLock, RVR_MISSING_OK, SearchSysCache1(), RenameStmt::subname, table_close(), table_open(), typenameTypeId(), and TYPEOID.

Referenced by ExecRenameStmt().

◆ RenameRelation()

ObjectAddress RenameRelation ( RenameStmt stmt)

Definition at line 3811 of file tablecmds.c.

3812 {
3813  bool is_index_stmt = stmt->renameType == OBJECT_INDEX;
3814  Oid relid;
3815  ObjectAddress address;
3816 
3817  /*
3818  * Grab an exclusive lock on the target table, index, sequence, view,
3819  * materialized view, or foreign table, which we will NOT release until
3820  * end of transaction.
3821  *
3822  * Lock level used here should match RenameRelationInternal, to avoid lock
3823  * escalation. However, because ALTER INDEX can be used with any relation
3824  * type, we mustn't believe without verification.
3825  */
3826  for (;;)
3827  {
3828  LOCKMODE lockmode;
3829  char relkind;
3830  bool obj_is_index;
3831 
3832  lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
3833 
3834  relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
3835  stmt->missing_ok ? RVR_MISSING_OK : 0,
3837  (void *) stmt);
3838 
3839  if (!OidIsValid(relid))
3840  {
3841  ereport(NOTICE,
3842  (errmsg("relation \"%s\" does not exist, skipping",
3843  stmt->relation->relname)));
3844  return InvalidObjectAddress;
3845  }
3846 
3847  /*
3848  * We allow mismatched statement and object types (e.g., ALTER INDEX
3849  * to rename a table), but we might've used the wrong lock level. If
3850  * that happens, retry with the correct lock level. We don't bother
3851  * if we already acquired AccessExclusiveLock with an index, however.
3852  */
3853  relkind = get_rel_relkind(relid);
3854  obj_is_index = (relkind == RELKIND_INDEX ||
3855  relkind == RELKIND_PARTITIONED_INDEX);
3856  if (obj_is_index || is_index_stmt == obj_is_index)
3857  break;
3858 
3859  UnlockRelationOid(relid, lockmode);
3860  is_index_stmt = obj_is_index;
3861  }
3862 
3863  /* Do the work */
3864  RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
3865 
3866  ObjectAddressSet(address, RelationRelationId, relid);
3867 
3868  return address;
3869 }
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:228
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3875

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

Referenced by ExecRenameStmt().

◆ RenameRelationInternal()

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

Definition at line 3875 of file tablecmds.c.

3876 {
3877  Relation targetrelation;
3878  Relation relrelation; /* for RELATION relation */
3879  HeapTuple reltup;
3880  Form_pg_class relform;
3881  Oid namespaceId;
3882 
3883  /*
3884  * Grab a lock on the target relation, which we will NOT release until end
3885  * of transaction. We need at least a self-exclusive lock so that
3886  * concurrent DDL doesn't overwrite the rename if they start updating
3887  * while still seeing the old version. The lock also guards against
3888  * triggering relcache reloads in concurrent sessions, which might not
3889  * handle this information changing under them. For indexes, we can use a
3890  * reduced lock level because RelationReloadIndexInfo() handles indexes
3891  * specially.
3892  */
3893  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
3894  namespaceId = RelationGetNamespace(targetrelation);
3895 
3896  /*
3897  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3898  */
3899  relrelation = table_open(RelationRelationId, RowExclusiveLock);
3900 
3901  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3902  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3903  elog(ERROR, "cache lookup failed for relation %u", myrelid);
3904  relform = (Form_pg_class) GETSTRUCT(reltup);
3905 
3906  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3907  ereport(ERROR,
3908  (errcode(ERRCODE_DUPLICATE_TABLE),
3909  errmsg("relation \"%s\" already exists",
3910  newrelname)));
3911 
3912  /*
3913  * RenameRelation is careful not to believe the caller's idea of the
3914  * relation kind being handled. We don't have to worry about this, but
3915  * let's not be totally oblivious to it. We can process an index as
3916  * not-an-index, but not the other way around.
3917  */
3918  Assert(!is_index ||
3919  is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3920  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
3921 
3922  /*
3923  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
3924  * because it's a copy...)
3925  */
3926  namestrcpy(&(relform->relname), newrelname);
3927 
3928  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3929 
3930  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
3931  InvalidOid, is_internal);
3932 
3933  heap_freetuple(reltup);
3934  table_close(relrelation, RowExclusiveLock);
3935 
3936  /*
3937  * Also rename the associated type, if any.
3938  */
3939  if (OidIsValid(targetrelation->rd_rel->reltype))
3940  RenameTypeInternal(targetrelation->rd_rel->reltype,
3941  newrelname, namespaceId);
3942 
3943  /*
3944  * Also rename the associated constraint, if any.
3945  */
3946  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3947  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3948  {
3949  Oid constraintId = get_index_constraint(myrelid);
3950 
3951  if (OidIsValid(constraintId))
3952  RenameConstraintById(constraintId, newrelname);
3953  }
3954 
3955  /*
3956  * Close rel, but keep lock!
3957  */
3958  relation_close(targetrelation, NoLock);
3959 }
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
Definition: objectaccess.h:200
void RenameConstraintById(Oid conId, const char *newname)
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:968
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:742

References AccessExclusiveLock, Assert(), 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().

◆ ResetRelRewrite()

void ResetRelRewrite ( Oid  myrelid)

Definition at line 3965 of file tablecmds.c.

3966 {
3967  Relation relrelation; /* for RELATION relation */
3968  HeapTuple reltup;
3969  Form_pg_class relform;
3970 
3971  /*
3972  * Find relation's pg_class tuple.
3973  */
3974  relrelation = table_open(RelationRelationId, RowExclusiveLock);
3975 
3976  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3977  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3978  elog(ERROR, "cache lookup failed for relation %u", myrelid);
3979  relform = (Form_pg_class) GETSTRUCT(reltup);
3980 
3981  /*
3982  * Update pg_class tuple.
3983  */
3984  relform->relrewrite = InvalidOid;
3985 
3986  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3987 
3988  heap_freetuple(reltup);
3989  table_close(relrelation, RowExclusiveLock);
3990 }

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().

◆ SetRelationHasSubclass()

void SetRelationHasSubclass ( Oid  relationId,
bool  relhassubclass 
)

Definition at line 3263 of file tablecmds.c.

3264 {
3265  Relation relationRelation;
3266  HeapTuple tuple;
3267  Form_pg_class classtuple;
3268 
3269  /*
3270  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3271  */
3272  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3273  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3274  if (!HeapTupleIsValid(tuple))
3275  elog(ERROR, "cache lookup failed for relation %u", relationId);
3276  classtuple = (Form_pg_class) GETSTRUCT(tuple);
3277 
3278  if (classtuple->relhassubclass != relhassubclass)
3279  {
3280  classtuple->relhassubclass = relhassubclass;
3281  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3282  }
3283  else
3284  {
3285  /* no need to change tuple, but force relcache rebuild anyway */
3287  }
3288 
3289  heap_freetuple(tuple);
3290  table_close(relationRelation, RowExclusiveLock);
3291 }
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1399

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().

◆ SetRelationTableSpace()

void SetRelationTableSpace ( Relation  rel,
Oid  newTableSpaceId,
RelFileNumber  newRelFilenumber 
)

Definition at line 3361 of file tablecmds.c.

3364 {
3365  Relation pg_class;
3366  HeapTuple tuple;
3367  Form_pg_class rd_rel;
3368  Oid reloid = RelationGetRelid(rel);
3369 
3370  Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3371 
3372  /* Get a modifiable copy of the relation's pg_class row. */
3373  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3374 
3375  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
3376  if (!HeapTupleIsValid(tuple))
3377  elog(ERROR, "cache lookup failed for relation %u", reloid);
3378  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3379 
3380  /* Update the pg_class row. */
3381  rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3382  InvalidOid : newTableSpaceId;
3383  if (RelFileNumberIsValid(newRelFilenumber))
3384  rd_rel->relfilenode = newRelFilenumber;
3385  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3386 
3387  /*
3388  * Record dependency on tablespace. This is only required for relations
3389  * that have no physical storage.
3390  */
3391  if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3392  changeDependencyOnTablespace(RelationRelationId, reloid,
3393  rd_rel->reltablespace);
3394 
3395  heap_freetuple(tuple);
3396  table_close(pg_class, RowExclusiveLock);
3397 }
void changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId)
Definition: pg_shdepend.c:382
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
Definition: tablecmds.c:3304

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

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