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, bool run_as_table_owner)
 
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 RangeVarCallbackOwnsTable (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
void RangeVarCallbackOwnsRelation (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
bool PartConstraintImpliedByRelConstraint (Relation scanrel, List *partConstraint)
 

Function Documentation

◆ AlterRelationNamespaceInternal()

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

Definition at line 17247 of file tablecmds.c.

17251 {
17252  HeapTuple classTup;
17253  Form_pg_class classForm;
17254  ObjectAddress thisobj;
17255  bool already_done = false;
17256 
17257  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
17258  if (!HeapTupleIsValid(classTup))
17259  elog(ERROR, "cache lookup failed for relation %u", relOid);
17260  classForm = (Form_pg_class) GETSTRUCT(classTup);
17261 
17262  Assert(classForm->relnamespace == oldNspOid);
17263 
17264  thisobj.classId = RelationRelationId;
17265  thisobj.objectId = relOid;
17266  thisobj.objectSubId = 0;
17267 
17268  /*
17269  * If the object has already been moved, don't move it again. If it's
17270  * already in the right place, don't move it, but still fire the object
17271  * access hook.
17272  */
17273  already_done = object_address_present(&thisobj, objsMoved);
17274  if (!already_done && oldNspOid != newNspOid)
17275  {
17276  /* check for duplicate name (more friendly than unique-index failure) */
17277  if (get_relname_relid(NameStr(classForm->relname),
17278  newNspOid) != InvalidOid)
17279  ereport(ERROR,
17280  (errcode(ERRCODE_DUPLICATE_TABLE),
17281  errmsg("relation \"%s\" already exists in schema \"%s\"",
17282  NameStr(classForm->relname),
17283  get_namespace_name(newNspOid))));
17284 
17285  /* classTup is a copy, so OK to scribble on */
17286  classForm->relnamespace = newNspOid;
17287 
17288  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
17289 
17290  /* Update dependency on schema if caller said so */
17291  if (hasDependEntry &&
17292  changeDependencyFor(RelationRelationId,
17293  relOid,
17294  NamespaceRelationId,
17295  oldNspOid,
17296  newNspOid) != 1)
17297  elog(ERROR, "could not change schema dependency for relation \"%s\"",
17298  NameStr(classForm->relname));
17299  }
17300  if (!already_done)
17301  {
17302  add_exact_object_address(&thisobj, objsMoved);
17303 
17304  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
17305  }
17306 
17307  heap_freetuple(classTup);
17308 }
#define NameStr(name)
Definition: c.h:735
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:1426
#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:313
Assert(fmt[strlen(fmt) - 1] !='\n')
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3348
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1889
#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:182
@ 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 4292 of file tablecmds.c.

4294 {
4295  Relation rel;
4296 
4297  /* Caller is required to provide an adequate lock. */
4298  rel = relation_open(context->relid, NoLock);
4299 
4300  CheckTableNotInUse(rel, "ALTER TABLE");
4301 
4302  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4303 }
#define stmt
Definition: indent_codes.h:59
#define NoLock
Definition: lockdefs.h:34
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:4205
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4628

References ATController(), CheckTableNotInUse(), NoLock, relation_open(), AlterTableUtilityContext::relid, and stmt.

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4366 of file tablecmds.c.

4367 {
4368  /*
4369  * This only works if we read catalog tables using MVCC snapshots.
4370  */
4371  ListCell *lcmd;
4373 
4374  foreach(lcmd, cmds)
4375  {
4376  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4377  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4378 
4379  switch (cmd->subtype)
4380  {
4381  /*
4382  * These subcommands rewrite the heap, so require full locks.
4383  */
4384  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4385  * to SELECT */
4386  case AT_SetAccessMethod: /* must rewrite heap */
4387  case AT_SetTableSpace: /* must rewrite heap */
4388  case AT_AlterColumnType: /* must rewrite heap */
4389  cmd_lockmode = AccessExclusiveLock;
4390  break;
4391 
4392  /*
4393  * These subcommands may require addition of toast tables. If
4394  * we add a toast table to a table currently being scanned, we
4395  * might miss data added to the new toast table by concurrent
4396  * insert transactions.
4397  */
4398  case AT_SetStorage: /* may add toast tables, see
4399  * ATRewriteCatalogs() */
4400  cmd_lockmode = AccessExclusiveLock;
4401  break;
4402 
4403  /*
4404  * Removing constraints can affect SELECTs that have been
4405  * optimized assuming the constraint holds true. See also
4406  * CloneFkReferenced.
4407  */
4408  case AT_DropConstraint: /* as DROP INDEX */
4409  case AT_DropNotNull: /* may change some SQL plans */
4410  cmd_lockmode = AccessExclusiveLock;
4411  break;
4412 
4413  /*
4414  * Subcommands that may be visible to concurrent SELECTs
4415  */
4416  case AT_DropColumn: /* change visible to SELECT */
4417  case AT_AddColumnToView: /* CREATE VIEW */
4418  case AT_DropOids: /* used to equiv to DropColumn */
4419  case AT_EnableAlwaysRule: /* may change SELECT rules */
4420  case AT_EnableReplicaRule: /* may change SELECT rules */
4421  case AT_EnableRule: /* may change SELECT rules */
4422  case AT_DisableRule: /* may change SELECT rules */
4423  cmd_lockmode = AccessExclusiveLock;
4424  break;
4425 
4426  /*
4427  * Changing owner may remove implicit SELECT privileges
4428  */
4429  case AT_ChangeOwner: /* change visible to SELECT */
4430  cmd_lockmode = AccessExclusiveLock;
4431  break;
4432 
4433  /*
4434  * Changing foreign table options may affect optimization.
4435  */
4436  case AT_GenericOptions:
4438  cmd_lockmode = AccessExclusiveLock;
4439  break;
4440 
4441  /*
4442  * These subcommands affect write operations only.
4443  */
4444  case AT_EnableTrig:
4445  case AT_EnableAlwaysTrig:
4446  case AT_EnableReplicaTrig:
4447  case AT_EnableTrigAll:
4448  case AT_EnableTrigUser:
4449  case AT_DisableTrig:
4450  case AT_DisableTrigAll:
4451  case AT_DisableTrigUser:
4452  cmd_lockmode = ShareRowExclusiveLock;
4453  break;
4454 
4455  /*
4456  * These subcommands affect write operations only. XXX
4457  * Theoretically, these could be ShareRowExclusiveLock.
4458  */
4459  case AT_ColumnDefault:
4461  case AT_AlterConstraint:
4462  case AT_AddIndex: /* from ADD CONSTRAINT */
4463  case AT_AddIndexConstraint:
4464  case AT_ReplicaIdentity:
4465  case AT_SetNotNull:
4466  case AT_SetAttNotNull:
4467  case AT_EnableRowSecurity:
4468  case AT_DisableRowSecurity:
4469  case AT_ForceRowSecurity:
4470  case AT_NoForceRowSecurity:
4471  case AT_AddIdentity:
4472  case AT_DropIdentity:
4473  case AT_SetIdentity:
4474  case AT_DropExpression:
4475  case AT_SetCompression:
4476  cmd_lockmode = AccessExclusiveLock;
4477  break;
4478 
4479  case AT_AddConstraint:
4480  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4481  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4482  if (IsA(cmd->def, Constraint))
4483  {
4484  Constraint *con = (Constraint *) cmd->def;
4485 
4486  switch (con->contype)
4487  {
4488  case CONSTR_EXCLUSION:
4489  case CONSTR_PRIMARY:
4490  case CONSTR_UNIQUE:
4491 
4492  /*
4493  * Cases essentially the same as CREATE INDEX. We
4494  * could reduce the lock strength to ShareLock if
4495  * we can work out how to allow concurrent catalog
4496  * updates. XXX Might be set down to
4497  * ShareRowExclusiveLock but requires further
4498  * analysis.
4499  */
4500  cmd_lockmode = AccessExclusiveLock;
4501  break;
4502  case CONSTR_FOREIGN:
4503 
4504  /*
4505  * We add triggers to both tables when we add a
4506  * Foreign Key, so the lock level must be at least
4507  * as strong as CREATE TRIGGER.
4508  */
4509  cmd_lockmode = ShareRowExclusiveLock;
4510  break;
4511 
4512  default:
4513  cmd_lockmode = AccessExclusiveLock;
4514  }
4515  }
4516  break;
4517 
4518  /*
4519  * These subcommands affect inheritance behaviour. Queries
4520  * started before us will continue to see the old inheritance
4521  * behaviour, while queries started after we commit will see
4522  * new behaviour. No need to prevent reads or writes to the
4523  * subtable while we hook it up though. Changing the TupDesc
4524  * may be a problem, so keep highest lock.
4525  */
4526  case AT_AddInherit:
4527  case AT_DropInherit:
4528  cmd_lockmode = AccessExclusiveLock;
4529  break;
4530 
4531  /*
4532  * These subcommands affect implicit row type conversion. They
4533  * have affects similar to CREATE/DROP CAST on queries. don't
4534  * provide for invalidating parse trees as a result of such
4535  * changes, so we keep these at AccessExclusiveLock.
4536  */
4537  case AT_AddOf:
4538  case AT_DropOf:
4539  cmd_lockmode = AccessExclusiveLock;
4540  break;
4541 
4542  /*
4543  * Only used by CREATE OR REPLACE VIEW which must conflict
4544  * with an SELECTs currently using the view.
4545  */
4546  case AT_ReplaceRelOptions:
4547  cmd_lockmode = AccessExclusiveLock;
4548  break;
4549 
4550  /*
4551  * These subcommands affect general strategies for performance
4552  * and maintenance, though don't change the semantic results
4553  * from normal data reads and writes. Delaying an ALTER TABLE
4554  * behind currently active writes only delays the point where
4555  * the new strategy begins to take effect, so there is no
4556  * benefit in waiting. In this case the minimum restriction
4557  * applies: we don't currently allow concurrent catalog
4558  * updates.
4559  */
4560  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4561  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4562  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4563  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4564  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4565  cmd_lockmode = ShareUpdateExclusiveLock;
4566  break;
4567 
4568  case AT_SetLogged:
4569  case AT_SetUnLogged:
4570  cmd_lockmode = AccessExclusiveLock;
4571  break;
4572 
4573  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4574  cmd_lockmode = ShareUpdateExclusiveLock;
4575  break;
4576 
4577  /*
4578  * Rel options are more complex than first appears. Options
4579  * are set here for tables, views and indexes; for historical
4580  * reasons these can all be used with ALTER TABLE, so we can't
4581  * decide between them using the basic grammar.
4582  */
4583  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4584  * getTables() */
4585  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4586  * getTables() */
4587  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4588  break;
4589 
4590  case AT_AttachPartition:
4591  cmd_lockmode = ShareUpdateExclusiveLock;
4592  break;
4593 
4594  case AT_DetachPartition:
4595  if (((PartitionCmd *) cmd->def)->concurrent)
4596  cmd_lockmode = ShareUpdateExclusiveLock;
4597  else
4598  cmd_lockmode = AccessExclusiveLock;
4599  break;
4600 
4602  cmd_lockmode = ShareUpdateExclusiveLock;
4603  break;
4604 
4605  default: /* oops */
4606  elog(ERROR, "unrecognized alter table type: %d",
4607  (int) cmd->subtype);
4608  break;
4609  }
4610 
4611  /*
4612  * Take the greatest lockmode from any subcommand
4613  */
4614  if (cmd_lockmode > lockmode)
4615  lockmode = cmd_lockmode;
4616  }
4617 
4618  return lockmode;
4619 }
int LOCKMODE
Definition: lockdefs.h:26
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define ShareRowExclusiveLock
Definition: lockdefs.h:41
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
@ CONSTR_FOREIGN
Definition: parsenodes.h:2571
@ CONSTR_UNIQUE
Definition: parsenodes.h:2569
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2570
@ CONSTR_PRIMARY
Definition: parsenodes.h:2568
@ AT_AddIndexConstraint
Definition: parsenodes.h:2233
@ AT_DropOf
Definition: parsenodes.h:2264
@ AT_SetOptions
Definition: parsenodes.h:2221
@ AT_DropIdentity
Definition: parsenodes.h:2276
@ AT_SetAttNotNull
Definition: parsenodes.h:2218
@ AT_DisableTrigUser
Definition: parsenodes.h:2256
@ AT_DropNotNull
Definition: parsenodes.h:2216
@ AT_AddOf
Definition: parsenodes.h:2263
@ AT_ResetOptions
Definition: parsenodes.h:2222
@ AT_ReplicaIdentity
Definition: parsenodes.h:2265
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2248
@ AT_EnableRowSecurity
Definition: parsenodes.h:2266
@ AT_AddColumnToView
Definition: parsenodes.h:2213
@ AT_ResetRelOptions
Definition: parsenodes.h:2247
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2251
@ AT_DropOids
Definition: parsenodes.h:2243
@ AT_SetIdentity
Definition: parsenodes.h:2275
@ AT_SetUnLogged
Definition: parsenodes.h:2242
@ AT_DisableTrig
Definition: parsenodes.h:2252
@ AT_SetCompression
Definition: parsenodes.h:2224
@ AT_DropExpression
Definition: parsenodes.h:2219
@ AT_AddIndex
Definition: parsenodes.h:2226
@ AT_EnableReplicaRule
Definition: parsenodes.h:2259
@ AT_DropConstraint
Definition: parsenodes.h:2234
@ AT_SetNotNull
Definition: parsenodes.h:2217
@ AT_ClusterOn
Definition: parsenodes.h:2239
@ AT_AddIdentity
Definition: parsenodes.h:2274
@ AT_ForceRowSecurity
Definition: parsenodes.h:2268
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2258
@ AT_SetAccessMethod
Definition: parsenodes.h:2244
@ AT_AlterColumnType
Definition: parsenodes.h:2236
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2273
@ AT_AddInherit
Definition: parsenodes.h:2261
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2230
@ AT_EnableTrig
Definition: parsenodes.h:2249
@ AT_DropColumn
Definition: parsenodes.h:2225
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2237
@ AT_DisableTrigAll
Definition: parsenodes.h:2254
@ AT_EnableRule
Definition: parsenodes.h:2257
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2269
@ AT_DetachPartition
Definition: parsenodes.h:2272
@ AT_SetStatistics
Definition: parsenodes.h:2220
@ AT_AttachPartition
Definition: parsenodes.h:2271
@ AT_AddConstraint
Definition: parsenodes.h:2228
@ AT_DropInherit
Definition: parsenodes.h:2262
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2250
@ AT_SetLogged
Definition: parsenodes.h:2241
@ AT_SetStorage
Definition: parsenodes.h:2223
@ AT_DisableRule
Definition: parsenodes.h:2260
@ AT_DisableRowSecurity
Definition: parsenodes.h:2267
@ AT_SetRelOptions
Definition: parsenodes.h:2246
@ AT_ChangeOwner
Definition: parsenodes.h:2238
@ AT_EnableTrigUser
Definition: parsenodes.h:2255
@ AT_ReAddConstraint
Definition: parsenodes.h:2229
@ AT_SetTableSpace
Definition: parsenodes.h:2245
@ AT_GenericOptions
Definition: parsenodes.h:2270
@ AT_ColumnDefault
Definition: parsenodes.h:2214
@ AT_CookedColumnDefault
Definition: parsenodes.h:2215
@ AT_AlterConstraint
Definition: parsenodes.h:2231
@ AT_EnableTrigAll
Definition: parsenodes.h:2253
@ AT_DropCluster
Definition: parsenodes.h:2240
@ AT_ValidateConstraint
Definition: parsenodes.h:2232
@ AT_AddColumn
Definition: parsenodes.h:2212
#define lfirst(lc)
Definition: pg_list.h:172
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2110
AlterTableType subtype
Definition: parsenodes.h:2290
ConstrType contype
Definition: parsenodes.h:2595
Definition: pg_list.h:54

References AccessExclusiveLock, 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_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_SetAttNotNull, 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 4321 of file tablecmds.c.

4322 {
4323  Relation rel;
4324  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4325 
4326  rel = relation_open(relid, lockmode);
4327 
4329 
4330  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4331 }
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4366

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4233 of file tablecmds.c.

4234 {
4235  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4236  stmt->missing_ok ? RVR_MISSING_OK : 0,
4238  (void *) stmt);
4239 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:221
@ RVR_MISSING_OK
Definition: namespace.h:71
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:17760

References RangeVarCallbackForAlterRelation(), RangeVarGetRelidExtended(), RVR_MISSING_OK, and stmt.

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 15175 of file tablecmds.c.

15176 {
15177  List *relations = NIL;
15178  ListCell *l;
15179  ScanKeyData key[1];
15180  Relation rel;
15181  TableScanDesc scan;
15182  HeapTuple tuple;
15183  Oid orig_tablespaceoid;
15184  Oid new_tablespaceoid;
15185  List *role_oids = roleSpecsToIds(stmt->roles);
15186 
15187  /* Ensure we were not asked to move something we can't */
15188  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
15189  stmt->objtype != OBJECT_MATVIEW)
15190  ereport(ERROR,
15191  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15192  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
15193 
15194  /* Get the orig and new tablespace OIDs */
15195  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
15196  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
15197 
15198  /* Can't move shared relations in to or out of pg_global */
15199  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
15200  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
15201  new_tablespaceoid == GLOBALTABLESPACE_OID)
15202  ereport(ERROR,
15203  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15204  errmsg("cannot move relations in to or out of pg_global tablespace")));
15205 
15206  /*
15207  * Must have CREATE rights on the new tablespace, unless it is the
15208  * database default tablespace (which all users implicitly have CREATE
15209  * rights on).
15210  */
15211  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
15212  {
15213  AclResult aclresult;
15214 
15215  aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
15216  ACL_CREATE);
15217  if (aclresult != ACLCHECK_OK)
15218  aclcheck_error(aclresult, OBJECT_TABLESPACE,
15219  get_tablespace_name(new_tablespaceoid));
15220  }
15221 
15222  /*
15223  * Now that the checks are done, check if we should set either to
15224  * InvalidOid because it is our database's default tablespace.
15225  */
15226  if (orig_tablespaceoid == MyDatabaseTableSpace)
15227  orig_tablespaceoid = InvalidOid;
15228 
15229  if (new_tablespaceoid == MyDatabaseTableSpace)
15230  new_tablespaceoid = InvalidOid;
15231 
15232  /* no-op */
15233  if (orig_tablespaceoid == new_tablespaceoid)
15234  return new_tablespaceoid;
15235 
15236  /*
15237  * Walk the list of objects in the tablespace and move them. This will
15238  * only find objects in our database, of course.
15239  */
15240  ScanKeyInit(&key[0],
15241  Anum_pg_class_reltablespace,
15242  BTEqualStrategyNumber, F_OIDEQ,
15243  ObjectIdGetDatum(orig_tablespaceoid));
15244 
15245  rel = table_open(RelationRelationId, AccessShareLock);
15246  scan = table_beginscan_catalog(rel, 1, key);
15247  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
15248  {
15249  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
15250  Oid relOid = relForm->oid;
15251 
15252  /*
15253  * Do not move objects in pg_catalog as part of this, if an admin
15254  * really wishes to do so, they can issue the individual ALTER
15255  * commands directly.
15256  *
15257  * Also, explicitly avoid any shared tables, temp tables, or TOAST
15258  * (TOAST will be moved with the main table).
15259  */
15260  if (IsCatalogNamespace(relForm->relnamespace) ||
15261  relForm->relisshared ||
15262  isAnyTempNamespace(relForm->relnamespace) ||
15263  IsToastNamespace(relForm->relnamespace))
15264  continue;
15265 
15266  /* Only move the object type requested */
15267  if ((stmt->objtype == OBJECT_TABLE &&
15268  relForm->relkind != RELKIND_RELATION &&
15269  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
15270  (stmt->objtype == OBJECT_INDEX &&
15271  relForm->relkind != RELKIND_INDEX &&
15272  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
15273  (stmt->objtype == OBJECT_MATVIEW &&
15274  relForm->relkind != RELKIND_MATVIEW))
15275  continue;
15276 
15277  /* Check if we are only moving objects owned by certain roles */
15278  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
15279  continue;
15280 
15281  /*
15282  * Handle permissions-checking here since we are locking the tables
15283  * and also to avoid doing a bunch of work only to fail part-way. Note
15284  * that permissions will also be checked by AlterTableInternal().
15285  *
15286  * Caller must be considered an owner on the table to move it.
15287  */
15288  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
15290  NameStr(relForm->relname));
15291 
15292  if (stmt->nowait &&
15294  ereport(ERROR,
15295  (errcode(ERRCODE_OBJECT_IN_USE),
15296  errmsg("aborting because lock on relation \"%s.%s\" is not available",
15297  get_namespace_name(relForm->relnamespace),
15298  NameStr(relForm->relname))));
15299  else
15301 
15302  /* Add to our list of objects to move */
15303  relations = lappend_oid(relations, relOid);
15304  }
15305 
15306  table_endscan(scan);
15308 
15309  if (relations == NIL)
15310  ereport(NOTICE,
15311  (errcode(ERRCODE_NO_DATA_FOUND),
15312  errmsg("no matching relations in tablespace \"%s\" found",
15313  orig_tablespaceoid == InvalidOid ? "(database default)" :
15314  get_tablespace_name(orig_tablespaceoid))));
15315 
15316  /* Everything is locked, loop through and move all of the relations. */
15317  foreach(l, relations)
15318  {
15319  List *cmds = NIL;
15321 
15322  cmd->subtype = AT_SetTableSpace;
15323  cmd->name = stmt->new_tablespacename;
15324 
15325  cmds = lappend(cmds, cmd);
15326 
15328  /* OID is set by AlterTableInternal */
15329  AlterTableInternal(lfirst_oid(l), cmds, false);
15331  }
15332 
15333  return new_tablespaceoid;
15334 }
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
@ ACLCHECK_NOT_OWNER
Definition: acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2669
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3760
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:3961
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
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1659
#define OidIsValid(objectId)
Definition: c.h:764
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:1086
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
#define AccessShareLock
Definition: lockdefs.h:36
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2007
Oid GetUserId(void)
Definition: miscinit.c:509
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3220
#define makeNode(_type_)
Definition: nodes.h:176
ObjectType get_relkind_objtype(char relkind)
@ OBJECT_MATVIEW
Definition: parsenodes.h:2143
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2162
@ OBJECT_INDEX
Definition: parsenodes.h:2140
@ OBJECT_TABLE
Definition: parsenodes.h:2161
#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:1009
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4321

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, NIL, NOTICE, object_aclcheck(), OBJECT_INDEX, OBJECT_MATVIEW, object_ownercheck(), OBJECT_TABLE, OBJECT_TABLESPACE, ObjectIdGetDatum(), OidIsValid, roleSpecsToIds(), ScanKeyInit(), stmt, 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 17137 of file tablecmds.c.

17138 {
17139  Relation rel;
17140  Oid relid;
17141  Oid oldNspOid;
17142  Oid nspOid;
17143  RangeVar *newrv;
17144  ObjectAddresses *objsMoved;
17145  ObjectAddress myself;
17146 
17148  stmt->missing_ok ? RVR_MISSING_OK : 0,
17150  (void *) stmt);
17151 
17152  if (!OidIsValid(relid))
17153  {
17154  ereport(NOTICE,
17155  (errmsg("relation \"%s\" does not exist, skipping",
17156  stmt->relation->relname)));
17157  return InvalidObjectAddress;
17158  }
17159 
17160  rel = relation_open(relid, NoLock);
17161 
17162  oldNspOid = RelationGetNamespace(rel);
17163 
17164  /* If it's an owned sequence, disallow moving it by itself. */
17165  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
17166  {
17167  Oid tableId;
17168  int32 colId;
17169 
17170  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
17171  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
17172  ereport(ERROR,
17173  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17174  errmsg("cannot move an owned sequence into another schema"),
17175  errdetail("Sequence \"%s\" is linked to table \"%s\".",
17177  get_rel_name(tableId))));
17178  }
17179 
17180  /* Get and lock schema OID and check its permissions. */
17181  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
17182  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
17183 
17184  /* common checks on switching namespaces */
17185  CheckSetNamespace(oldNspOid, nspOid);
17186 
17187  objsMoved = new_object_addresses();
17188  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
17189  free_object_addresses(objsMoved);
17190 
17191  ObjectAddressSet(myself, RelationRelationId, relid);
17192 
17193  if (oldschema)
17194  *oldschema = oldNspOid;
17195 
17196  /* close rel, but keep lock until commit */
17197  relation_close(rel, NoLock);
17198 
17199  return myself;
17200 }
signed int int32
Definition: c.h:483
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:1932
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:425
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:519
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2992
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:538
#define RelationGetNamespace(relation)
Definition: rel.h:545
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Form_pg_class rd_rel
Definition: rel.h:111
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17208

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

Referenced by ExecAlterObjectSchemaStmt().

◆ AlterTableNamespaceInternal()

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

Definition at line 17208 of file tablecmds.c.

17210 {
17211  Relation classRel;
17212 
17213  Assert(objsMoved != NULL);
17214 
17215  /* OK, modify the pg_class row and pg_depend entry */
17216  classRel = table_open(RelationRelationId, RowExclusiveLock);
17217 
17218  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
17219  nspOid, true, objsMoved);
17220 
17221  /* Fix the table's row type too, if it has one */
17222  if (OidIsValid(rel->rd_rel->reltype))
17223  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
17224  nspOid, false, false, objsMoved);
17225 
17226  /* Fix other dependent stuff */
17227  if (rel->rd_rel->relkind == RELKIND_RELATION ||
17228  rel->rd_rel->relkind == RELKIND_MATVIEW ||
17229  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
17230  {
17231  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
17232  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
17233  objsMoved, AccessExclusiveLock);
17234  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
17235  false, objsMoved);
17236  }
17237 
17238  table_close(classRel, RowExclusiveLock);
17239 }
#define RowExclusiveLock
Definition: lockdefs.h:38
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
#define RelationGetRelid(relation)
Definition: rel.h:504
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17247
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:17362
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17317
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3946

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 17637 of file tablecmds.c.

17639 {
17640  ListCell *cur_item;
17641 
17642  foreach(cur_item, on_commits)
17643  {
17644  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
17645 
17646  if (!isCommit && oc->creating_subid == mySubid)
17647  {
17648  /* cur_item must be removed */
17650  pfree(oc);
17651  }
17652  else
17653  {
17654  /* cur_item must be preserved */
17655  if (oc->creating_subid == mySubid)
17656  oc->creating_subid = parentSubid;
17657  if (oc->deleting_subid == mySubid)
17658  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
17659  }
17660  }
17661 }
#define InvalidSubTransactionId
Definition: c.h:647
void pfree(void *pointer)
Definition: mcxt.c:1456
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:390
SubTransactionId creating_subid
Definition: tablecmds.c:124
SubTransactionId deleting_subid
Definition: tablecmds.c:125
static List * on_commits
Definition: tablecmds.c:128

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 17605 of file tablecmds.c.

17606 {
17607  ListCell *cur_item;
17608 
17609  foreach(cur_item, on_commits)
17610  {
17611  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
17612 
17613  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
17615  {
17616  /* cur_item must be removed */
17618  pfree(oc);
17619  }
17620  else
17621  {
17622  /* cur_item must be preserved */
17625  }
17626  }
17627 }

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 14374 of file tablecmds.c.

14375 {
14376  Relation target_rel;
14377  Relation class_rel;
14378  HeapTuple tuple;
14379  Form_pg_class tuple_class;
14380 
14381  /*
14382  * Get exclusive lock till end of transaction on the target table. Use
14383  * relation_open so that we can work on indexes and sequences.
14384  */
14385  target_rel = relation_open(relationOid, lockmode);
14386 
14387  /* Get its pg_class tuple, too */
14388  class_rel = table_open(RelationRelationId, RowExclusiveLock);
14389 
14390  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
14391  if (!HeapTupleIsValid(tuple))
14392  elog(ERROR, "cache lookup failed for relation %u", relationOid);
14393  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
14394 
14395  /* Can we change the ownership of this tuple? */
14396  switch (tuple_class->relkind)
14397  {
14398  case RELKIND_RELATION:
14399  case RELKIND_VIEW:
14400  case RELKIND_MATVIEW:
14401  case RELKIND_FOREIGN_TABLE:
14402  case RELKIND_PARTITIONED_TABLE:
14403  /* ok to change owner */
14404  break;
14405  case RELKIND_INDEX:
14406  if (!recursing)
14407  {
14408  /*
14409  * Because ALTER INDEX OWNER used to be allowed, and in fact
14410  * is generated by old versions of pg_dump, we give a warning
14411  * and do nothing rather than erroring out. Also, to avoid
14412  * unnecessary chatter while restoring those old dumps, say
14413  * nothing at all if the command would be a no-op anyway.
14414  */
14415  if (tuple_class->relowner != newOwnerId)
14416  ereport(WARNING,
14417  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14418  errmsg("cannot change owner of index \"%s\"",
14419  NameStr(tuple_class->relname)),
14420  errhint("Change the ownership of the index's table instead.")));
14421  /* quick hack to exit via the no-op path */
14422  newOwnerId = tuple_class->relowner;
14423  }
14424  break;
14425  case RELKIND_PARTITIONED_INDEX:
14426  if (recursing)
14427  break;
14428  ereport(ERROR,
14429  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14430  errmsg("cannot change owner of index \"%s\"",
14431  NameStr(tuple_class->relname)),
14432  errhint("Change the ownership of the index's table instead.")));
14433  break;
14434  case RELKIND_SEQUENCE:
14435  if (!recursing &&
14436  tuple_class->relowner != newOwnerId)
14437  {
14438  /* if it's an owned sequence, disallow changing it by itself */
14439  Oid tableId;
14440  int32 colId;
14441 
14442  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
14443  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
14444  ereport(ERROR,
14445  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14446  errmsg("cannot change owner of sequence \"%s\"",
14447  NameStr(tuple_class->relname)),
14448  errdetail("Sequence \"%s\" is linked to table \"%s\".",
14449  NameStr(tuple_class->relname),
14450  get_rel_name(tableId))));
14451  }
14452  break;
14453  case RELKIND_COMPOSITE_TYPE:
14454  if (recursing)
14455  break;
14456  ereport(ERROR,
14457  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14458  errmsg("\"%s\" is a composite type",
14459  NameStr(tuple_class->relname)),
14460  errhint("Use ALTER TYPE instead.")));
14461  break;
14462  case RELKIND_TOASTVALUE:
14463  if (recursing)
14464  break;
14465  /* FALL THRU */
14466  default:
14467  ereport(ERROR,
14468  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14469  errmsg("cannot change owner of relation \"%s\"",
14470  NameStr(tuple_class->relname)),
14471  errdetail_relkind_not_supported(tuple_class->relkind)));
14472  }
14473 
14474  /*
14475  * If the new owner is the same as the existing owner, consider the
14476  * command to have succeeded. This is for dump restoration purposes.
14477  */
14478  if (tuple_class->relowner != newOwnerId)
14479  {
14480  Datum repl_val[Natts_pg_class];
14481  bool repl_null[Natts_pg_class];
14482  bool repl_repl[Natts_pg_class];
14483  Acl *newAcl;
14484  Datum aclDatum;
14485  bool isNull;
14486  HeapTuple newtuple;
14487 
14488  /* skip permission checks when recursing to index or toast table */
14489  if (!recursing)
14490  {
14491  /* Superusers can always do it */
14492  if (!superuser())
14493  {
14494  Oid namespaceOid = tuple_class->relnamespace;
14495  AclResult aclresult;
14496 
14497  /* Otherwise, must be owner of the existing object */
14498  if (!object_ownercheck(RelationRelationId, relationOid, GetUserId()))
14500  RelationGetRelationName(target_rel));
14501 
14502  /* Must be able to become new owner */
14503  check_can_set_role(GetUserId(), newOwnerId);
14504 
14505  /* New owner must have CREATE privilege on namespace */
14506  aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId,
14507  ACL_CREATE);
14508  if (aclresult != ACLCHECK_OK)
14509  aclcheck_error(aclresult, OBJECT_SCHEMA,
14510  get_namespace_name(namespaceOid));
14511  }
14512  }
14513 
14514  memset(repl_null, false, sizeof(repl_null));
14515  memset(repl_repl, false, sizeof(repl_repl));
14516 
14517  repl_repl[Anum_pg_class_relowner - 1] = true;
14518  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
14519 
14520  /*
14521  * Determine the modified ACL for the new owner. This is only
14522  * necessary when the ACL is non-null.
14523  */
14524  aclDatum = SysCacheGetAttr(RELOID, tuple,
14525  Anum_pg_class_relacl,
14526  &isNull);
14527  if (!isNull)
14528  {
14529  newAcl = aclnewowner(DatumGetAclP(aclDatum),
14530  tuple_class->relowner, newOwnerId);
14531  repl_repl[Anum_pg_class_relacl - 1] = true;
14532  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
14533  }
14534 
14535  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
14536 
14537  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
14538 
14539  heap_freetuple(newtuple);
14540 
14541  /*
14542  * We must similarly update any per-column ACLs to reflect the new
14543  * owner; for neatness reasons that's split out as a subroutine.
14544  */
14545  change_owner_fix_column_acls(relationOid,
14546  tuple_class->relowner,
14547  newOwnerId);
14548 
14549  /*
14550  * Update owner dependency reference, if any. A composite type has
14551  * none, because it's tracked for the pg_type entry instead of here;
14552  * indexes and TOAST tables don't have their own entries either.
14553  */
14554  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
14555  tuple_class->relkind != RELKIND_INDEX &&
14556  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
14557  tuple_class->relkind != RELKIND_TOASTVALUE)
14558  changeDependencyOnOwner(RelationRelationId, relationOid,
14559  newOwnerId);
14560 
14561  /*
14562  * Also change the ownership of the table's row type, if it has one
14563  */
14564  if (OidIsValid(tuple_class->reltype))
14565  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
14566 
14567  /*
14568  * If we are operating on a table or materialized view, also change
14569  * the ownership of any indexes and sequences that belong to the
14570  * relation, as well as its toast table (if it has one).
14571  */
14572  if (tuple_class->relkind == RELKIND_RELATION ||
14573  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
14574  tuple_class->relkind == RELKIND_MATVIEW ||
14575  tuple_class->relkind == RELKIND_TOASTVALUE)
14576  {
14577  List *index_oid_list;
14578  ListCell *i;
14579 
14580  /* Find all the indexes belonging to this relation */
14581  index_oid_list = RelationGetIndexList(target_rel);
14582 
14583  /* For each index, recursively change its ownership */
14584  foreach(i, index_oid_list)
14585  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
14586 
14587  list_free(index_oid_list);
14588  }
14589 
14590  /* If it has a toast table, recurse to change its ownership */
14591  if (tuple_class->reltoastrelid != InvalidOid)
14592  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
14593  true, lockmode);
14594 
14595  /* If it has dependent sequences, recurse to change them too */
14596  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
14597  }
14598 
14599  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
14600 
14601  ReleaseSysCache(tuple);
14602  table_close(class_rel, RowExclusiveLock);
14603  relation_close(target_rel, NoLock);
14604 }
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1087
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5018
#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:1201
int i
Definition: isn.c:73
void list_free(List *list)
Definition: list.c:1545
@ OBJECT_SCHEMA
Definition: parsenodes.h:2156
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:530
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4740
bool superuser(void)
Definition: superuser.c:46
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:868
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:820
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1081
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:14374
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:14678
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:14613
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3816

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 6816 of file tablecmds.c.

6817 {
6818  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
6819  bool typeOk = false;
6820 
6821  if (typ->typtype == TYPTYPE_COMPOSITE)
6822  {
6823  Relation typeRelation;
6824 
6825  Assert(OidIsValid(typ->typrelid));
6826  typeRelation = relation_open(typ->typrelid, AccessShareLock);
6827  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6828 
6829  /*
6830  * Close the parent rel, but keep our AccessShareLock on it until xact
6831  * commit. That will prevent someone else from deleting or ALTERing
6832  * the type before the typed table creation/conversion commits.
6833  */
6834  relation_close(typeRelation, NoLock);
6835  }
6836  if (!typeOk)
6837  ereport(ERROR,
6838  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6839  errmsg("type %s is not a composite type",
6840  format_type_be(typ->oid))));
6841 }
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
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 3488 of file tablecmds.c.

3489 {
3490  Oid oldTableSpaceId;
3491 
3492  /*
3493  * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3494  * stored as 0.
3495  */
3496  oldTableSpaceId = rel->rd_rel->reltablespace;
3497  if (newTableSpaceId == oldTableSpaceId ||
3498  (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3499  return false;
3500 
3501  /*
3502  * We cannot support moving mapped relations into different tablespaces.
3503  * (In particular this eliminates all shared catalogs.)
3504  */
3505  if (RelationIsMapped(rel))
3506  ereport(ERROR,
3507  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3508  errmsg("cannot move system relation \"%s\"",
3509  RelationGetRelationName(rel))));
3510 
3511  /* Cannot move a non-shared relation into pg_global */
3512  if (newTableSpaceId == GLOBALTABLESPACE_OID)
3513  ereport(ERROR,
3514  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3515  errmsg("only shared relations can be placed in pg_global tablespace")));
3516 
3517  /*
3518  * Do not allow moving temp tables of other backends ... their local
3519  * buffer manager is not going to cope.
3520  */
3521  if (RELATION_IS_OTHER_TEMP(rel))
3522  ereport(ERROR,
3523  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3524  errmsg("cannot move temporary tables of other sessions")));
3525 
3526  return true;
3527 }
#define RelationIsMapped(relation)
Definition: rel.h:553
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:659

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 4205 of file tablecmds.c.

4206 {
4207  int expected_refcnt;
4208 
4209  expected_refcnt = rel->rd_isnailed ? 2 : 1;
4210  if (rel->rd_refcnt != expected_refcnt)
4211  ereport(ERROR,
4212  (errcode(ERRCODE_OBJECT_IN_USE),
4213  /* translator: first %s is a SQL command, eg ALTER TABLE */
4214  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
4215  stmt, RelationGetRelationName(rel))));
4216 
4217  if (rel->rd_rel->relkind != RELKIND_INDEX &&
4218  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
4220  ereport(ERROR,
4221  (errcode(ERRCODE_OBJECT_IN_USE),
4222  /* translator: first %s is a SQL command, eg ALTER TABLE */
4223  errmsg("cannot %s \"%s\" because it has pending trigger events",
4224  stmt, RelationGetRelationName(rel))));
4225 }
int rd_refcnt
Definition: rel.h:59
bool rd_isnailed
Definition: rel.h:62
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5962

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

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

◆ DefineRelation()

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

Definition at line 674 of file tablecmds.c.

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

References AccessExclusiveLock, AccessShareLock, ACL_CREATE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, addNSItemToQuery(), addRangeTableEntryForRelation(), AddRelationNewConstraints(), AddRelationNotNullConstraints(), 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, 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, InSecurityRestrictedOperation(), InvalidOid, CookedConstraint::is_local, CookedConstraint::is_no_inherit, lappend(), lappend_oid(), lfirst, lfirst_int, 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, OidIsValid, ONCOMMIT_NOOP, ParseState::p_sourcetext, palloc(), PARTITION_MAX_KEYS, partitioned_table_reloptions(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelid, RawColumnDefault::raw_default, ColumnDef::raw_default, RelationData::rd_index, RelationData::rd_rel, relation_close(), relation_open(), RelationGetDescr, RelationGetIndexList(), RelationGetPartitionDesc(), RelationGetRelationName, RelationGetRelid, relname, set_attnotnull(), ShareUpdateExclusiveLock, CookedConstraint::skip_validation, stmt, ColumnDef::storage_name, StoreCatalogInheritance(), StorePartitionBound(), StorePartitionKey(), strlcpy(), table_close(), table_open(), 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 1685 of file tablecmds.c.

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

References AccessExclusiveLock, 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, stmt, 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,
bool  run_as_table_owner 
)

Definition at line 1809 of file tablecmds.c.

1814 {
1815  List *rels;
1816  List *seq_relids = NIL;
1817  HTAB *ft_htab = NULL;
1818  EState *estate;
1819  ResultRelInfo *resultRelInfos;
1820  ResultRelInfo *resultRelInfo;
1821  SubTransactionId mySubid;
1822  ListCell *cell;
1823  Oid *logrelids;
1824 
1825  /*
1826  * Check the explicitly-specified relations.
1827  *
1828  * In CASCADE mode, suck in all referencing relations as well. This
1829  * requires multiple iterations to find indirectly-dependent relations. At
1830  * each phase, we need to exclusive-lock new rels before looking for their
1831  * dependencies, else we might miss something. Also, we check each rel as
1832  * soon as we open it, to avoid a faux pas such as holding lock for a long
1833  * time on a rel we have no permissions for.
1834  */
1835  rels = list_copy(explicit_rels);
1836  if (behavior == DROP_CASCADE)
1837  {
1838  for (;;)
1839  {
1840  List *newrelids;
1841 
1842  newrelids = heap_truncate_find_FKs(relids);
1843  if (newrelids == NIL)
1844  break; /* nothing else to add */
1845 
1846  foreach(cell, newrelids)
1847  {
1848  Oid relid = lfirst_oid(cell);
1849  Relation rel;
1850 
1851  rel = table_open(relid, AccessExclusiveLock);
1852  ereport(NOTICE,
1853  (errmsg("truncate cascades to table \"%s\"",
1854  RelationGetRelationName(rel))));
1855  truncate_check_rel(relid, rel->rd_rel);
1856  truncate_check_perms(relid, rel->rd_rel);
1858  rels = lappend(rels, rel);
1859  relids = lappend_oid(relids, relid);
1860 
1861  /* Log this relation only if needed for logical decoding */
1862  if (RelationIsLogicallyLogged(rel))
1863  relids_logged = lappend_oid(relids_logged, relid);
1864  }
1865  }
1866  }
1867 
1868  /*
1869  * Check foreign key references. In CASCADE mode, this should be
1870  * unnecessary since we just pulled in all the references; but as a
1871  * cross-check, do it anyway if in an Assert-enabled build.
1872  */
1873 #ifdef USE_ASSERT_CHECKING
1874  heap_truncate_check_FKs(rels, false);
1875 #else
1876  if (behavior == DROP_RESTRICT)
1877  heap_truncate_check_FKs(rels, false);
1878 #endif
1879 
1880  /*
1881  * If we are asked to restart sequences, find all the sequences, lock them
1882  * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1883  * We want to do this early since it's pointless to do all the truncation
1884  * work only to fail on sequence permissions.
1885  */
1886  if (restart_seqs)
1887  {
1888  foreach(cell, rels)
1889  {
1890  Relation rel = (Relation) lfirst(cell);
1891  List *seqlist = getOwnedSequences(RelationGetRelid(rel));
1892  ListCell *seqcell;
1893 
1894  foreach(seqcell, seqlist)
1895  {
1896  Oid seq_relid = lfirst_oid(seqcell);
1897  Relation seq_rel;
1898 
1899  seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1900 
1901  /* This check must match AlterSequence! */
1902  if (!object_ownercheck(RelationRelationId, seq_relid, GetUserId()))
1904  RelationGetRelationName(seq_rel));
1905 
1906  seq_relids = lappend_oid(seq_relids, seq_relid);
1907 
1908  relation_close(seq_rel, NoLock);
1909  }
1910  }
1911  }
1912 
1913  /* Prepare to catch AFTER triggers. */
1915 
1916  /*
1917  * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1918  * each relation. We don't need to call ExecOpenIndices, though.
1919  *
1920  * We put the ResultRelInfos in the es_opened_result_relations list, even
1921  * though we don't have a range table and don't populate the
1922  * es_result_relations array. That's a bit bogus, but it's enough to make
1923  * ExecGetTriggerResultRel() find them.
1924  */
1925  estate = CreateExecutorState();
1926  resultRelInfos = (ResultRelInfo *)
1927  palloc(list_length(rels) * sizeof(ResultRelInfo));
1928  resultRelInfo = resultRelInfos;
1929  foreach(cell, rels)
1930  {
1931  Relation rel = (Relation) lfirst(cell);
1932 
1933  InitResultRelInfo(resultRelInfo,
1934  rel,
1935  0, /* dummy rangetable index */
1936  NULL,
1937  0);
1938  estate->es_opened_result_relations =
1939  lappend(estate->es_opened_result_relations, resultRelInfo);
1940  resultRelInfo++;
1941  }
1942 
1943  /*
1944  * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
1945  * truncating (this is because one of them might throw an error). Also, if
1946  * we were to allow them to prevent statement execution, that would need
1947  * to be handled here.
1948  */
1949  resultRelInfo = resultRelInfos;
1950  foreach(cell, rels)
1951  {
1952  UserContext ucxt;
1953 
1954  if (run_as_table_owner)
1955  SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
1956  &ucxt);
1957  ExecBSTruncateTriggers(estate, resultRelInfo);
1958  if (run_as_table_owner)
1959  RestoreUserContext(&ucxt);
1960  resultRelInfo++;
1961  }
1962 
1963  /*
1964  * OK, truncate each table.
1965  */
1966  mySubid = GetCurrentSubTransactionId();
1967 
1968  foreach(cell, rels)
1969  {
1970  Relation rel = (Relation) lfirst(cell);
1971 
1972  /* Skip partitioned tables as there is nothing to do */
1973  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1974  continue;
1975 
1976  /*
1977  * Build the lists of foreign tables belonging to each foreign server
1978  * and pass each list to the foreign data wrapper's callback function,
1979  * so that each server can truncate its all foreign tables in bulk.
1980  * Each list is saved as a single entry in a hash table that uses the
1981  * server OID as lookup key.
1982  */
1983  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1984  {
1986  bool found;
1987  ForeignTruncateInfo *ft_info;
1988 
1989  /* First time through, initialize hashtable for foreign tables */
1990  if (!ft_htab)
1991  {
1992  HASHCTL hctl;
1993 
1994  memset(&hctl, 0, sizeof(HASHCTL));
1995  hctl.keysize = sizeof(Oid);
1996  hctl.entrysize = sizeof(ForeignTruncateInfo);
1997  hctl.hcxt = CurrentMemoryContext;
1998 
1999  ft_htab = hash_create("TRUNCATE for Foreign Tables",
2000  32, /* start small and extend */
2001  &hctl,
2003  }
2004 
2005  /* Find or create cached entry for the foreign table */
2006  ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
2007  if (!found)
2008  {
2009  ft_info->serverid = serverid;
2010  ft_info->rels = NIL;
2011  }
2012 
2013  /*
2014  * Save the foreign table in the entry of the server that the
2015  * foreign table belongs to.
2016  */
2017  ft_info->rels = lappend(ft_info->rels, rel);
2018  continue;
2019  }
2020 
2021  /*
2022  * Normally, we need a transaction-safe truncation here. However, if
2023  * the table was either created in the current (sub)transaction or has
2024  * a new relfilenumber in the current (sub)transaction, then we can
2025  * just truncate it in-place, because a rollback would cause the whole
2026  * table or the current physical file to be thrown away anyway.
2027  */
2028  if (rel->rd_createSubid == mySubid ||
2029  rel->rd_newRelfilelocatorSubid == mySubid)
2030  {
2031  /* Immediate, non-rollbackable truncation is OK */
2032  heap_truncate_one_rel(rel);
2033  }
2034  else
2035  {
2036  Oid heap_relid;
2037  Oid toast_relid;
2038  ReindexParams reindex_params = {0};
2039 
2040  /*
2041  * This effectively deletes all rows in the table, and may be done
2042  * in a serializable transaction. In that case we must record a
2043  * rw-conflict in to this transaction from each transaction
2044  * holding a predicate lock on the table.
2045  */
2047 
2048  /*
2049  * Need the full transaction-safe pushups.
2050  *
2051  * Create a new empty storage file for the relation, and assign it
2052  * as the relfilenumber value. The old storage file is scheduled
2053  * for deletion at commit.
2054  */
2055  RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
2056 
2057  heap_relid = RelationGetRelid(rel);
2058 
2059  /*
2060  * The same for the toast table, if any.
2061  */
2062  toast_relid = rel->rd_rel->reltoastrelid;
2063  if (OidIsValid(toast_relid))
2064  {
2065  Relation toastrel = relation_open(toast_relid,
2067 
2068  RelationSetNewRelfilenumber(toastrel,
2069  toastrel->rd_rel->relpersistence);
2070  table_close(toastrel, NoLock);
2071  }
2072 
2073  /*
2074  * Reconstruct the indexes to match, and we're done.
2075  */
2077  &reindex_params);
2078  }
2079 
2080  pgstat_count_truncate(rel);
2081  }
2082 
2083  /* Now go through the hash table, and truncate foreign tables */
2084  if (ft_htab)
2085  {
2086  ForeignTruncateInfo *ft_info;
2087  HASH_SEQ_STATUS seq;
2088 
2089  hash_seq_init(&seq, ft_htab);
2090 
2091  PG_TRY();
2092  {
2093  while ((ft_info = hash_seq_search(&seq)) != NULL)
2094  {
2095  FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2096 
2097  /* truncate_check_rel() has checked that already */
2098  Assert(routine->ExecForeignTruncate != NULL);
2099 
2100  routine->ExecForeignTruncate(ft_info->rels,
2101  behavior,
2102  restart_seqs);
2103  }
2104  }
2105  PG_FINALLY();
2106  {
2107  hash_destroy(ft_htab);
2108  }
2109  PG_END_TRY();
2110  }
2111 
2112  /*
2113  * Restart owned sequences if we were asked to.
2114  */
2115  foreach(cell, seq_relids)
2116  {
2117  Oid seq_relid = lfirst_oid(cell);
2118 
2119  ResetSequence(seq_relid);
2120  }
2121 
2122  /*
2123  * Write a WAL record to allow this set of actions to be logically
2124  * decoded.
2125  *
2126  * Assemble an array of relids so we can write a single WAL record for the
2127  * whole action.
2128  */
2129  if (relids_logged != NIL)
2130  {
2131  xl_heap_truncate xlrec;
2132  int i = 0;
2133 
2134  /* should only get here if wal_level >= logical */
2136 
2137  logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
2138  foreach(cell, relids_logged)
2139  logrelids[i++] = lfirst_oid(cell);
2140 
2141  xlrec.dbId = MyDatabaseId;
2142  xlrec.nrelids = list_length(relids_logged);
2143  xlrec.flags = 0;
2144  if (behavior == DROP_CASCADE)
2145  xlrec.flags |= XLH_TRUNCATE_CASCADE;
2146  if (restart_seqs)
2148 
2149  XLogBeginInsert();
2150  XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
2151  XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
2152 
2154 
2155  (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
2156  }
2157 
2158  /*
2159  * Process all AFTER STATEMENT TRUNCATE triggers.
2160  */
2161  resultRelInfo = resultRelInfos;
2162  foreach(cell, rels)
2163  {
2164  UserContext ucxt;
2165 
2166  if (run_as_table_owner)
2167  SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2168  &ucxt);
2169  ExecASTruncateTriggers(estate, resultRelInfo);
2170  if (run_as_table_owner)
2171  RestoreUserContext(&ucxt);
2172  resultRelInfo++;
2173  }
2174 
2175  /* Handle queued AFTER triggers */
2176  AfterTriggerEndQuery(estate);
2177 
2178  /* We can clean up the EState now */
2179  FreeExecutorState(estate);
2180 
2181  /*
2182  * Close any rels opened by CASCADE (can't do this while EState still
2183  * holds refs)
2184  */
2185  rels = list_difference_ptr(rels, explicit_rels);
2186  foreach(cell, rels)
2187  {
2188  Relation rel = (Relation) lfirst(cell);
2189 
2190  table_close(rel, NoLock);
2191  }
2192 }
uint32 SubTransactionId
Definition: c.h:645
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:1225
EState * CreateExecutorState(void)
Definition: execUtils.c:93
void FreeExecutorState(EState *estate)
Definition: execUtils.c:194
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:3513
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3418
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3374
#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, const ReindexParams *params)
Definition: index.c:3862
#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:2194
@ DROP_RESTRICT
Definition: parsenodes.h:2193
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2157
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:935
void pgstat_count_truncate(Relation rel)
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4353
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition: relcache.c:3710
void ResetSequence(Oid seq_relid)
Definition: sequence.c:261
List * es_opened_result_relations
Definition: execnodes.h:637
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:104
SubTransactionId rd_createSubid
Definition: rel.h:103
Relation ri_RelationDesc
Definition: execnodes.h:450
struct ForeignTruncateInfo ForeignTruncateInfo
static void truncate_check_perms(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2247
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3210
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3257
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:5026
void AfterTriggerBeginQuery(void)
Definition: trigger.c:5006
void SwitchToUntrustedUser(Oid userid, UserContext *context)
Definition: usercontext.c:33
void RestoreUserContext(UserContext *context)
Definition: usercontext.c:87
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:461
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:443
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(), RestoreUserContext(), ResultRelInfo::ri_RelationDesc, ForeignTruncateInfo::serverid, SizeOfHeapTruncate, SwitchToUntrustedUser(), 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 6609 of file tablecmds.c.

6611 {
6612  Relation depRel;
6613  ScanKeyData key[2];
6614  SysScanDesc depScan;
6615  HeapTuple depTup;
6616 
6617  /* since this function recurses, it could be driven to stack overflow */
6619 
6620  /*
6621  * We scan pg_depend to find those things that depend on the given type.
6622  * (We assume we can ignore refobjsubid for a type.)
6623  */
6624  depRel = table_open(DependRelationId, AccessShareLock);
6625 
6626  ScanKeyInit(&key[0],
6627  Anum_pg_depend_refclassid,
6628  BTEqualStrategyNumber, F_OIDEQ,
6629  ObjectIdGetDatum(TypeRelationId));
6630  ScanKeyInit(&key[1],
6631  Anum_pg_depend_refobjid,
6632  BTEqualStrategyNumber, F_OIDEQ,
6633  ObjectIdGetDatum(typeOid));
6634 
6635  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6636  NULL, 2, key);
6637 
6638  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6639  {
6640  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6641  Relation rel;
6642  TupleDesc tupleDesc;
6643  Form_pg_attribute att;
6644 
6645  /* Check for directly dependent types */
6646  if (pg_depend->classid == TypeRelationId)
6647  {
6648  /*
6649  * This must be an array, domain, or range containing the given
6650  * type, so recursively check for uses of this type. Note that
6651  * any error message will mention the original type not the
6652  * container; this is intentional.
6653  */
6654  find_composite_type_dependencies(pg_depend->objid,
6655  origRelation, origTypeName);
6656  continue;
6657  }
6658 
6659  /* Else, ignore dependees that aren't relations */
6660  if (pg_depend->classid != RelationRelationId)
6661  continue;
6662 
6663  rel = relation_open(pg_depend->objid, AccessShareLock);
6664  tupleDesc = RelationGetDescr(rel);
6665 
6666  /*
6667  * If objsubid identifies a specific column, refer to that in error
6668  * messages. Otherwise, search to see if there's a user column of the
6669  * type. (We assume system columns are never of interesting types.)
6670  * The search is needed because an index containing an expression
6671  * column of the target type will just be recorded as a whole-relation
6672  * dependency. If we do not find a column of the type, the dependency
6673  * must indicate that the type is transiently referenced in an index
6674  * expression but not stored on disk, which we assume is OK, just as
6675  * we do for references in views. (It could also be that the target
6676  * type is embedded in some container type that is stored in an index
6677  * column, but the previous recursion should catch such cases.)
6678  */
6679  if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
6680  att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
6681  else
6682  {
6683  att = NULL;
6684  for (int attno = 1; attno <= tupleDesc->natts; attno++)
6685  {
6686  att = TupleDescAttr(tupleDesc, attno - 1);
6687  if (att->atttypid == typeOid && !att->attisdropped)
6688  break;
6689  att = NULL;
6690  }
6691  if (att == NULL)
6692  {
6693  /* No such column, so assume OK */
6695  continue;
6696  }
6697  }
6698 
6699  /*
6700  * We definitely should reject if the relation has storage. If it's
6701  * partitioned, then perhaps we don't have to reject: if there are
6702  * partitions then we'll fail when we find one, else there is no
6703  * stored data to worry about. However, it's possible that the type
6704  * change would affect conclusions about whether the type is sortable
6705  * or hashable and thus (if it's a partitioning column) break the
6706  * partitioning rule. For now, reject for partitioned rels too.
6707  */
6708  if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
6709  RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
6710  {
6711  if (origTypeName)
6712  ereport(ERROR,
6713  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6714  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6715  origTypeName,
6717  NameStr(att->attname))));
6718  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6719  ereport(ERROR,
6720  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6721  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6722  RelationGetRelationName(origRelation),
6724  NameStr(att->attname))));
6725  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
6726  ereport(ERROR,
6727  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6728  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
6729  RelationGetRelationName(origRelation),
6731  NameStr(att->attname))));
6732  else
6733  ereport(ERROR,
6734  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6735  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
6736  RelationGetRelationName(origRelation),
6738  NameStr(att->attname))));
6739  }
6740  else if (OidIsValid(rel->rd_rel->reltype))
6741  {
6742  /*
6743  * A view or composite type itself isn't a problem, but we must
6744  * recursively check for indirect dependencies via its rowtype.
6745  */
6747  origRelation, origTypeName);
6748  }
6749 
6751  }
6752 
6753  systable_endscan(depScan);
6754 
6756 }
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:3523
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:6609

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

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

◆ PartConstraintImpliedByRelConstraint()

bool PartConstraintImpliedByRelConstraint ( Relation  scanrel,
List partConstraint 
)

Definition at line 18211 of file tablecmds.c.

18213 {
18214  List *existConstraint = NIL;
18215  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
18216  int i;
18217 
18218  if (constr && constr->has_not_null)
18219  {
18220  int natts = scanrel->rd_att->natts;
18221 
18222  for (i = 1; i <= natts; i++)
18223  {
18224  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
18225 
18226  if (att->attnotnull && !att->attisdropped)
18227  {
18228  NullTest *ntest = makeNode(NullTest);
18229 
18230  ntest->arg = (Expr *) makeVar(1,
18231  i,
18232  att->atttypid,
18233  att->atttypmod,
18234  att->attcollation,
18235  0);
18236  ntest->nulltesttype = IS_NOT_NULL;
18237 
18238  /*
18239  * argisrow=false is correct even for a composite column,
18240  * because attnotnull does not represent a SQL-spec IS NOT
18241  * NULL test in such a case, just IS DISTINCT FROM NULL.
18242  */
18243  ntest->argisrow = false;
18244  ntest->location = -1;
18245  existConstraint = lappend(existConstraint, ntest);
18246  }
18247  }
18248  }
18249 
18250  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
18251 }
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
@ IS_NOT_NULL
Definition: primnodes.h:1686
NullTestType nulltesttype
Definition: primnodes.h:1693
int location
Definition: primnodes.h:1696
Expr * arg
Definition: primnodes.h:1692
TupleDesc rd_att
Definition: rel.h:112
bool has_not_null
Definition: tupdesc.h:44
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:18264

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 17506 of file tablecmds.c.

17507 {
17508  ListCell *l;
17509  List *oids_to_truncate = NIL;
17510  List *oids_to_drop = NIL;
17511 
17512  foreach(l, on_commits)
17513  {
17514  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
17515 
17516  /* Ignore entry if already dropped in this xact */
17518  continue;
17519 
17520  switch (oc->oncommit)
17521  {
17522  case ONCOMMIT_NOOP:
17524  /* Do nothing (there shouldn't be such entries, actually) */
17525  break;
17526  case ONCOMMIT_DELETE_ROWS:
17527 
17528  /*
17529  * If this transaction hasn't accessed any temporary
17530  * relations, we can skip truncating ON COMMIT DELETE ROWS
17531  * tables, as they must still be empty.
17532  */
17534  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
17535  break;
17536  case ONCOMMIT_DROP:
17537  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
17538  break;
17539  }
17540  }
17541 
17542  /*
17543  * Truncate relations before dropping so that all dependencies between
17544  * relations are removed after they are worked on. Doing it like this
17545  * might be a waste as it is possible that a relation being truncated will
17546  * be dropped anyway due to its parent being dropped, but this makes the
17547  * code more robust because of not having to re-check that the relation
17548  * exists at truncation time.
17549  */
17550  if (oids_to_truncate != NIL)
17551  heap_truncate(oids_to_truncate);
17552 
17553  if (oids_to_drop != NIL)
17554  {
17555  ObjectAddresses *targetObjects = new_object_addresses();
17556 
17557  foreach(l, oids_to_drop)
17558  {
17559  ObjectAddress object;
17560 
17561  object.classId = RelationRelationId;
17562  object.objectId = lfirst_oid(l);
17563  object.objectSubId = 0;
17564 
17565  Assert(!object_address_present(&object, targetObjects));
17566 
17567  add_exact_object_address(&object, targetObjects);
17568  }
17569 
17570  /*
17571  * Since this is an automatic drop, rather than one directly initiated
17572  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
17573  */
17574  performMultipleDeletions(targetObjects, DROP_CASCADE,
17576 
17577 #ifdef USE_ASSERT_CHECKING
17578 
17579  /*
17580  * Note that table deletion will call remove_on_commit_action, so the
17581  * entry should get marked as deleted.
17582  */
17583  foreach(l, on_commits)
17584  {
17585  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
17586 
17587  if (oc->oncommit != ONCOMMIT_DROP)
17588  continue;
17589 
17591  }
17592 #endif
17593  }
17594 }
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:3333
@ 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:115
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().

◆ RangeVarCallbackOwnsRelation()

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

Definition at line 17728 of file tablecmds.c.

17730 {
17731  HeapTuple tuple;
17732 
17733  /* Nothing to do if the relation was not found. */
17734  if (!OidIsValid(relId))
17735  return;
17736 
17737  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
17738  if (!HeapTupleIsValid(tuple)) /* should not happen */
17739  elog(ERROR, "cache lookup failed for relation %u", relId);
17740 
17741  if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
17743  relation->relname);
17744 
17745  if (!allowSystemTableMods &&
17746  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
17747  ereport(ERROR,
17748  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
17749  errmsg("permission denied: \"%s\" is a system catalog",
17750  relation->relname)));
17751 
17752  ReleaseSysCache(tuple);
17753 }
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:87
char * relname
Definition: primnodes.h:74

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

◆ RangeVarCallbackOwnsTable()

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

Definition at line 17672 of file tablecmds.c.

17674 {
17675  char relkind;
17676 
17677  /* Nothing to do if the relation was not found. */
17678  if (!OidIsValid(relId))
17679  return;
17680 
17681  /*
17682  * If the relation does exist, check whether it's an index. But note that
17683  * the relation might have been dropped between the time we did the name
17684  * lookup and now. In that case, there's nothing to do.
17685  */
17686  relkind = get_rel_relkind(relId);
17687  if (!relkind)
17688  return;
17689  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
17690  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
17691  ereport(ERROR,
17692  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
17693  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
17694 
17695  /* Check permissions */
17696  if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
17698 }

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

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

◆ register_on_commit_action()

void register_on_commit_action ( Oid  relid,
OnCommitAction  action 
)

Definition at line 17447 of file tablecmds.c.

17448 {
17449  OnCommitItem *oc;
17450  MemoryContext oldcxt;
17451 
17452  /*
17453  * We needn't bother registering the relation unless there is an ON COMMIT
17454  * action we need to take.
17455  */
17457  return;
17458 
17460 
17461  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
17462  oc->relid = relid;
17463  oc->oncommit = action;
17466 
17467  /*
17468  * We use lcons() here so that ON COMMIT actions are processed in reverse
17469  * order of registration. That might not be essential but it seems
17470  * reasonable.
17471  */
17472  on_commits = lcons(oc, on_commits);
17473 
17474  MemoryContextSwitchTo(oldcxt);
17475 }
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 17483 of file tablecmds.c.

17484 {
17485  ListCell *l;
17486 
17487  foreach(l, on_commits)
17488  {
17489  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
17490 
17491  if (oc->relid == relid)
17492  {
17494  break;
17495  }
17496  }
17497 }

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 1362 of file tablecmds.c.

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

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 3801 of file tablecmds.c.

3802 {
3803  Oid relid;
3805  ObjectAddress address;
3806 
3807  /* lock level taken here should match renameatt_internal */
3809  stmt->missing_ok ? RVR_MISSING_OK : 0,
3811  NULL);
3812 
3813  if (!OidIsValid(relid))
3814  {
3815  ereport(NOTICE,
3816  (errmsg("relation \"%s\" does not exist, skipping",
3817  stmt->relation->relname)));
3818  return InvalidObjectAddress;
3819  }
3820 
3821  attnum =
3822  renameatt_internal(relid,
3823  stmt->subname, /* old att name */
3824  stmt->newname, /* new att name */
3825  stmt->relation->inh, /* recursive? */
3826  false, /* recursing? */
3827  0, /* expected inhcount */
3828  stmt->behavior);
3829 
3830  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3831 
3832  return address;
3833 }
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:3636
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3781

References AccessExclusiveLock, attnum, ereport, errmsg(), InvalidObjectAddress, NOTICE, ObjectAddressSubSet, OidIsValid, RangeVarCallbackForRenameAttribute(), RangeVarGetRelidExtended(), renameatt_internal(), RVR_MISSING_OK, and stmt.

Referenced by ExecRenameStmt().

◆ RenameConstraint()

ObjectAddress RenameConstraint ( RenameStmt stmt)

Definition at line 3948 of file tablecmds.c.

3949 {
3950  Oid relid = InvalidOid;
3951  Oid typid = InvalidOid;
3952 
3953  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3954  {
3955  Relation rel;
3956  HeapTuple tup;
3957 
3958  typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
3959  rel = table_open(TypeRelationId, RowExclusiveLock);
3960  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3961  if (!HeapTupleIsValid(tup))
3962  elog(ERROR, "cache lookup failed for type %u", typid);
3963  checkDomainOwner(tup);
3964  ReleaseSysCache(tup);
3965  table_close(rel, NoLock);
3966  }
3967  else
3968  {
3969  /* lock level taken here should match rename_constraint_internal */
3971  stmt->missing_ok ? RVR_MISSING_OK : 0,
3973  NULL);
3974  if (!OidIsValid(relid))
3975  {
3976  ereport(NOTICE,
3977  (errmsg("relation \"%s\" does not exist, skipping",
3978  stmt->relation->relname)));
3979  return InvalidObjectAddress;
3980  }
3981  }
3982 
3983  return
3984  rename_constraint_internal(relid, typid,
3985  stmt->subname,
3986  stmt->newname,
3987  (stmt->relation &&
3988  stmt->relation->inh), /* recursive? */
3989  false, /* recursing? */
3990  0 /* expected inhcount */ );
3991 }
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:459
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2133
@ 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:3839
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3415

References AccessExclusiveLock, castNode, checkDomainOwner(), elog(), ereport, errmsg(), ERROR, HeapTupleIsValid, InvalidObjectAddress, InvalidOid, makeTypeNameFromNameList(), NoLock, NOTICE, OBJECT_DOMCONSTRAINT, ObjectIdGetDatum(), OidIsValid, RangeVarCallbackForRenameAttribute(), RangeVarGetRelidExtended(), ReleaseSysCache(), rename_constraint_internal(), RowExclusiveLock, RVR_MISSING_OK, SearchSysCache1(), stmt, table_close(), table_open(), typenameTypeId(), and TYPEOID.

Referenced by ExecRenameStmt().

◆ RenameRelation()

ObjectAddress RenameRelation ( RenameStmt stmt)

Definition at line 3998 of file tablecmds.c.

3999 {
4000  bool is_index_stmt = stmt->renameType == OBJECT_INDEX;
4001  Oid relid;
4002  ObjectAddress address;
4003 
4004  /*
4005  * Grab an exclusive lock on the target table, index, sequence, view,
4006  * materialized view, or foreign table, which we will NOT release until
4007  * end of transaction.
4008  *
4009  * Lock level used here should match RenameRelationInternal, to avoid lock
4010  * escalation. However, because ALTER INDEX can be used with any relation
4011  * type, we mustn't believe without verification.
4012  */
4013  for (;;)
4014  {
4015  LOCKMODE lockmode;
4016  char relkind;
4017  bool obj_is_index;
4018 
4019  lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
4020 
4021  relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
4022  stmt->missing_ok ? RVR_MISSING_OK : 0,
4024  (void *) stmt);
4025 
4026  if (!OidIsValid(relid))
4027  {
4028  ereport(NOTICE,
4029  (errmsg("relation \"%s\" does not exist, skipping",
4030  stmt->relation->relname)));
4031  return InvalidObjectAddress;
4032  }
4033 
4034  /*
4035  * We allow mismatched statement and object types (e.g., ALTER INDEX
4036  * to rename a table), but we might've used the wrong lock level. If
4037  * that happens, retry with the correct lock level. We don't bother
4038  * if we already acquired AccessExclusiveLock with an index, however.
4039  */
4040  relkind = get_rel_relkind(relid);
4041  obj_is_index = (relkind == RELKIND_INDEX ||
4042  relkind == RELKIND_PARTITIONED_INDEX);
4043  if (obj_is_index || is_index_stmt == obj_is_index)
4044  break;
4045 
4046  UnlockRelationOid(relid, lockmode);
4047  is_index_stmt = obj_is_index;
4048  }
4049 
4050  /* Do the work */
4051  RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
4052 
4053  ObjectAddressSet(address, RelationRelationId, relid);
4054 
4055  return address;
4056 }
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:4062

References AccessExclusiveLock, ereport, errmsg(), get_rel_relkind(), InvalidObjectAddress, NOTICE, OBJECT_INDEX, ObjectAddressSet, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetRelidExtended(), RenameRelationInternal(), RVR_MISSING_OK, ShareUpdateExclusiveLock, stmt, and UnlockRelationOid().

Referenced by ExecRenameStmt().

◆ RenameRelationInternal()

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

Definition at line 4062 of file tablecmds.c.

4063 {
4064  Relation targetrelation;
4065  Relation relrelation; /* for RELATION relation */
4066  HeapTuple reltup;
4067  Form_pg_class relform;
4068  Oid namespaceId;
4069 
4070  /*
4071  * Grab a lock on the target relation, which we will NOT release until end
4072  * of transaction. We need at least a self-exclusive lock so that
4073  * concurrent DDL doesn't overwrite the rename if they start updating
4074  * while still seeing the old version. The lock also guards against
4075  * triggering relcache reloads in concurrent sessions, which might not
4076  * handle this information changing under them. For indexes, we can use a
4077  * reduced lock level because RelationReloadIndexInfo() handles indexes
4078  * specially.
4079  */
4080  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
4081  namespaceId = RelationGetNamespace(targetrelation);
4082 
4083  /*
4084  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
4085  */
4086  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4087 
4088  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4089  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4090  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4091  relform = (Form_pg_class) GETSTRUCT(reltup);
4092 
4093  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
4094  ereport(ERROR,
4095  (errcode(ERRCODE_DUPLICATE_TABLE),
4096  errmsg("relation \"%s\" already exists",
4097  newrelname)));
4098 
4099  /*
4100  * RenameRelation is careful not to believe the caller's idea of the
4101  * relation kind being handled. We don't have to worry about this, but
4102  * let's not be totally oblivious to it. We can process an index as
4103  * not-an-index, but not the other way around.
4104  */
4105  Assert(!is_index ||
4106  is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4107  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
4108 
4109  /*
4110  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
4111  * because it's a copy...)
4112  */
4113  namestrcpy(&(relform->relname), newrelname);
4114 
4115  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4116 
4117  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
4118  InvalidOid, is_internal);
4119 
4120  heap_freetuple(reltup);
4121  table_close(relrelation, RowExclusiveLock);
4122 
4123  /*
4124  * Also rename the associated type, if any.
4125  */
4126  if (OidIsValid(targetrelation->rd_rel->reltype))
4127  RenameTypeInternal(targetrelation->rd_rel->reltype,
4128  newrelname, namespaceId);
4129 
4130  /*
4131  * Also rename the associated constraint, if any.
4132  */
4133  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4134  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4135  {
4136  Oid constraintId = get_index_constraint(myrelid);
4137 
4138  if (OidIsValid(constraintId))
4139  RenameConstraintById(constraintId, newrelname);
4140  }
4141 
4142  /*
4143  * Close rel, but keep lock!
4144  */
4145  relation_close(targetrelation, NoLock);
4146 }
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 4152 of file tablecmds.c.

4153 {
4154  Relation relrelation; /* for RELATION relation */
4155  HeapTuple reltup;
4156  Form_pg_class relform;
4157 
4158  /*
4159  * Find relation's pg_class tuple.
4160  */
4161  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4162 
4163  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4164  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4165  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4166  relform = (Form_pg_class) GETSTRUCT(reltup);
4167 
4168  /*
4169  * Update pg_class tuple.
4170  */
4171  relform->relrewrite = InvalidOid;
4172 
4173  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4174 
4175  heap_freetuple(reltup);
4176  table_close(relrelation, RowExclusiveLock);
4177 }

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 3447 of file tablecmds.c.

3448 {
3449  Relation relationRelation;
3450  HeapTuple tuple;
3451  Form_pg_class classtuple;
3452 
3453  /*
3454  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3455  */
3456  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3457  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3458  if (!HeapTupleIsValid(tuple))
3459  elog(ERROR, "cache lookup failed for relation %u", relationId);
3460  classtuple = (Form_pg_class) GETSTRUCT(tuple);
3461 
3462  if (classtuple->relhassubclass != relhassubclass)
3463  {
3464  classtuple->relhassubclass = relhassubclass;
3465  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3466  }
3467  else
3468  {
3469  /* no need to change tuple, but force relcache rebuild anyway */
3471  }
3472 
3473  heap_freetuple(tuple);
3474  table_close(relationRelation, RowExclusiveLock);
3475 }
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 3545 of file tablecmds.c.

3548 {
3549  Relation pg_class;
3550  HeapTuple tuple;
3551  Form_pg_class rd_rel;
3552  Oid reloid = RelationGetRelid(rel);
3553 
3554  Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3555 
3556  /* Get a modifiable copy of the relation's pg_class row. */
3557  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3558 
3559  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
3560  if (!HeapTupleIsValid(tuple))
3561  elog(ERROR, "cache lookup failed for relation %u", reloid);
3562  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3563 
3564  /* Update the pg_class row. */
3565  rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3566  InvalidOid : newTableSpaceId;
3567  if (RelFileNumberIsValid(newRelFilenumber))
3568  rd_rel->relfilenode = newRelFilenumber;
3569  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3570 
3571  /*
3572  * Record dependency on tablespace. This is only required for relations
3573  * that have no physical storage.
3574  */
3575  if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3576  changeDependencyOnTablespace(RelationRelationId, reloid,
3577  rd_rel->reltablespace);
3578 
3579  heap_freetuple(tuple);
3580  table_close(pg_class, RowExclusiveLock);
3581 }
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:3488

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