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)
 
TupleDesc BuildDescForRelation (const List *columns)
 
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 17672 of file tablecmds.c.

17676 {
17677  HeapTuple classTup;
17678  Form_pg_class classForm;
17679  ObjectAddress thisobj;
17680  bool already_done = false;
17681 
17682  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
17683  if (!HeapTupleIsValid(classTup))
17684  elog(ERROR, "cache lookup failed for relation %u", relOid);
17685  classForm = (Form_pg_class) GETSTRUCT(classTup);
17686 
17687  Assert(classForm->relnamespace == oldNspOid);
17688 
17689  thisobj.classId = RelationRelationId;
17690  thisobj.objectId = relOid;
17691  thisobj.objectSubId = 0;
17692 
17693  /*
17694  * If the object has already been moved, don't move it again. If it's
17695  * already in the right place, don't move it, but still fire the object
17696  * access hook.
17697  */
17698  already_done = object_address_present(&thisobj, objsMoved);
17699  if (!already_done && oldNspOid != newNspOid)
17700  {
17701  /* check for duplicate name (more friendly than unique-index failure) */
17702  if (get_relname_relid(NameStr(classForm->relname),
17703  newNspOid) != InvalidOid)
17704  ereport(ERROR,
17705  (errcode(ERRCODE_DUPLICATE_TABLE),
17706  errmsg("relation \"%s\" already exists in schema \"%s\"",
17707  NameStr(classForm->relname),
17708  get_namespace_name(newNspOid))));
17709 
17710  /* classTup is a copy, so OK to scribble on */
17711  classForm->relnamespace = newNspOid;
17712 
17713  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
17714 
17715  /* Update dependency on schema if caller said so */
17716  if (hasDependEntry &&
17717  changeDependencyFor(RelationRelationId,
17718  relOid,
17719  NamespaceRelationId,
17720  oldNspOid,
17721  newNspOid) != 1)
17722  elog(ERROR, "could not change schema dependency for relation \"%s\"",
17723  NameStr(classForm->relname));
17724  }
17725  if (!already_done)
17726  {
17727  add_exact_object_address(&thisobj, objsMoved);
17728 
17729  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
17730  }
17731 
17732  heap_freetuple(classTup);
17733 }
#define NameStr(name)
Definition: c.h:735
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2648
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2588
int errcode(int sqlerrcode)
Definition: elog.c:860
int errmsg(const char *fmt,...)
Definition: elog.c:1075
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#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:3321
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1862
#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:86

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

4424 {
4425  Relation rel;
4426 
4427  /* Caller is required to provide an adequate lock. */
4428  rel = relation_open(context->relid, NoLock);
4429 
4430  CheckTableNotInUse(rel, "ALTER TABLE");
4431 
4432  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4433 }
#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:4335
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4759

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

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4496 of file tablecmds.c.

4497 {
4498  /*
4499  * This only works if we read catalog tables using MVCC snapshots.
4500  */
4501  ListCell *lcmd;
4503 
4504  foreach(lcmd, cmds)
4505  {
4506  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4507  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4508 
4509  switch (cmd->subtype)
4510  {
4511  /*
4512  * These subcommands rewrite the heap, so require full locks.
4513  */
4514  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4515  * to SELECT */
4516  case AT_SetAccessMethod: /* must rewrite heap */
4517  case AT_SetTableSpace: /* must rewrite heap */
4518  case AT_AlterColumnType: /* must rewrite heap */
4519  cmd_lockmode = AccessExclusiveLock;
4520  break;
4521 
4522  /*
4523  * These subcommands may require addition of toast tables. If
4524  * we add a toast table to a table currently being scanned, we
4525  * might miss data added to the new toast table by concurrent
4526  * insert transactions.
4527  */
4528  case AT_SetStorage: /* may add toast tables, see
4529  * ATRewriteCatalogs() */
4530  cmd_lockmode = AccessExclusiveLock;
4531  break;
4532 
4533  /*
4534  * Removing constraints can affect SELECTs that have been
4535  * optimized assuming the constraint holds true. See also
4536  * CloneFkReferenced.
4537  */
4538  case AT_DropConstraint: /* as DROP INDEX */
4539  case AT_DropNotNull: /* may change some SQL plans */
4540  cmd_lockmode = AccessExclusiveLock;
4541  break;
4542 
4543  /*
4544  * Subcommands that may be visible to concurrent SELECTs
4545  */
4546  case AT_DropColumn: /* change visible to SELECT */
4547  case AT_AddColumnToView: /* CREATE VIEW */
4548  case AT_DropOids: /* used to equiv to DropColumn */
4549  case AT_EnableAlwaysRule: /* may change SELECT rules */
4550  case AT_EnableReplicaRule: /* may change SELECT rules */
4551  case AT_EnableRule: /* may change SELECT rules */
4552  case AT_DisableRule: /* may change SELECT rules */
4553  cmd_lockmode = AccessExclusiveLock;
4554  break;
4555 
4556  /*
4557  * Changing owner may remove implicit SELECT privileges
4558  */
4559  case AT_ChangeOwner: /* change visible to SELECT */
4560  cmd_lockmode = AccessExclusiveLock;
4561  break;
4562 
4563  /*
4564  * Changing foreign table options may affect optimization.
4565  */
4566  case AT_GenericOptions:
4568  cmd_lockmode = AccessExclusiveLock;
4569  break;
4570 
4571  /*
4572  * These subcommands affect write operations only.
4573  */
4574  case AT_EnableTrig:
4575  case AT_EnableAlwaysTrig:
4576  case AT_EnableReplicaTrig:
4577  case AT_EnableTrigAll:
4578  case AT_EnableTrigUser:
4579  case AT_DisableTrig:
4580  case AT_DisableTrigAll:
4581  case AT_DisableTrigUser:
4582  cmd_lockmode = ShareRowExclusiveLock;
4583  break;
4584 
4585  /*
4586  * These subcommands affect write operations only. XXX
4587  * Theoretically, these could be ShareRowExclusiveLock.
4588  */
4589  case AT_ColumnDefault:
4591  case AT_AlterConstraint:
4592  case AT_AddIndex: /* from ADD CONSTRAINT */
4593  case AT_AddIndexConstraint:
4594  case AT_ReplicaIdentity:
4595  case AT_SetNotNull:
4596  case AT_SetAttNotNull:
4597  case AT_EnableRowSecurity:
4598  case AT_DisableRowSecurity:
4599  case AT_ForceRowSecurity:
4600  case AT_NoForceRowSecurity:
4601  case AT_AddIdentity:
4602  case AT_DropIdentity:
4603  case AT_SetIdentity:
4604  case AT_SetExpression:
4605  case AT_DropExpression:
4606  case AT_SetCompression:
4607  cmd_lockmode = AccessExclusiveLock;
4608  break;
4609 
4610  case AT_AddConstraint:
4611  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4612  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4613  if (IsA(cmd->def, Constraint))
4614  {
4615  Constraint *con = (Constraint *) cmd->def;
4616 
4617  switch (con->contype)
4618  {
4619  case CONSTR_EXCLUSION:
4620  case CONSTR_PRIMARY:
4621  case CONSTR_UNIQUE:
4622 
4623  /*
4624  * Cases essentially the same as CREATE INDEX. We
4625  * could reduce the lock strength to ShareLock if
4626  * we can work out how to allow concurrent catalog
4627  * updates. XXX Might be set down to
4628  * ShareRowExclusiveLock but requires further
4629  * analysis.
4630  */
4631  cmd_lockmode = AccessExclusiveLock;
4632  break;
4633  case CONSTR_FOREIGN:
4634 
4635  /*
4636  * We add triggers to both tables when we add a
4637  * Foreign Key, so the lock level must be at least
4638  * as strong as CREATE TRIGGER.
4639  */
4640  cmd_lockmode = ShareRowExclusiveLock;
4641  break;
4642 
4643  default:
4644  cmd_lockmode = AccessExclusiveLock;
4645  }
4646  }
4647  break;
4648 
4649  /*
4650  * These subcommands affect inheritance behaviour. Queries
4651  * started before us will continue to see the old inheritance
4652  * behaviour, while queries started after we commit will see
4653  * new behaviour. No need to prevent reads or writes to the
4654  * subtable while we hook it up though. Changing the TupDesc
4655  * may be a problem, so keep highest lock.
4656  */
4657  case AT_AddInherit:
4658  case AT_DropInherit:
4659  cmd_lockmode = AccessExclusiveLock;
4660  break;
4661 
4662  /*
4663  * These subcommands affect implicit row type conversion. They
4664  * have affects similar to CREATE/DROP CAST on queries. don't
4665  * provide for invalidating parse trees as a result of such
4666  * changes, so we keep these at AccessExclusiveLock.
4667  */
4668  case AT_AddOf:
4669  case AT_DropOf:
4670  cmd_lockmode = AccessExclusiveLock;
4671  break;
4672 
4673  /*
4674  * Only used by CREATE OR REPLACE VIEW which must conflict
4675  * with an SELECTs currently using the view.
4676  */
4677  case AT_ReplaceRelOptions:
4678  cmd_lockmode = AccessExclusiveLock;
4679  break;
4680 
4681  /*
4682  * These subcommands affect general strategies for performance
4683  * and maintenance, though don't change the semantic results
4684  * from normal data reads and writes. Delaying an ALTER TABLE
4685  * behind currently active writes only delays the point where
4686  * the new strategy begins to take effect, so there is no
4687  * benefit in waiting. In this case the minimum restriction
4688  * applies: we don't currently allow concurrent catalog
4689  * updates.
4690  */
4691  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4692  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4693  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4694  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4695  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4696  cmd_lockmode = ShareUpdateExclusiveLock;
4697  break;
4698 
4699  case AT_SetLogged:
4700  case AT_SetUnLogged:
4701  cmd_lockmode = AccessExclusiveLock;
4702  break;
4703 
4704  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4705  cmd_lockmode = ShareUpdateExclusiveLock;
4706  break;
4707 
4708  /*
4709  * Rel options are more complex than first appears. Options
4710  * are set here for tables, views and indexes; for historical
4711  * reasons these can all be used with ALTER TABLE, so we can't
4712  * decide between them using the basic grammar.
4713  */
4714  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4715  * getTables() */
4716  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4717  * getTables() */
4718  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4719  break;
4720 
4721  case AT_AttachPartition:
4722  cmd_lockmode = ShareUpdateExclusiveLock;
4723  break;
4724 
4725  case AT_DetachPartition:
4726  if (((PartitionCmd *) cmd->def)->concurrent)
4727  cmd_lockmode = ShareUpdateExclusiveLock;
4728  else
4729  cmd_lockmode = AccessExclusiveLock;
4730  break;
4731 
4733  cmd_lockmode = ShareUpdateExclusiveLock;
4734  break;
4735 
4736  default: /* oops */
4737  elog(ERROR, "unrecognized alter table type: %d",
4738  (int) cmd->subtype);
4739  break;
4740  }
4741 
4742  /*
4743  * Take the greatest lockmode from any subcommand
4744  */
4745  if (cmd_lockmode > lockmode)
4746  lockmode = cmd_lockmode;
4747  }
4748 
4749  return lockmode;
4750 }
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:158
@ CONSTR_FOREIGN
Definition: parsenodes.h:2548
@ CONSTR_UNIQUE
Definition: parsenodes.h:2546
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2547
@ CONSTR_PRIMARY
Definition: parsenodes.h:2545
@ AT_AddIndexConstraint
Definition: parsenodes.h:2210
@ AT_DropOf
Definition: parsenodes.h:2241
@ AT_SetOptions
Definition: parsenodes.h:2198
@ AT_DropIdentity
Definition: parsenodes.h:2253
@ AT_SetAttNotNull
Definition: parsenodes.h:2194
@ AT_DisableTrigUser
Definition: parsenodes.h:2233
@ AT_DropNotNull
Definition: parsenodes.h:2192
@ AT_AddOf
Definition: parsenodes.h:2240
@ AT_ResetOptions
Definition: parsenodes.h:2199
@ AT_ReplicaIdentity
Definition: parsenodes.h:2242
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2225
@ AT_EnableRowSecurity
Definition: parsenodes.h:2243
@ AT_AddColumnToView
Definition: parsenodes.h:2189
@ AT_ResetRelOptions
Definition: parsenodes.h:2224
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2228
@ AT_DropOids
Definition: parsenodes.h:2220
@ AT_SetIdentity
Definition: parsenodes.h:2252
@ AT_SetUnLogged
Definition: parsenodes.h:2219
@ AT_DisableTrig
Definition: parsenodes.h:2229
@ AT_SetCompression
Definition: parsenodes.h:2201
@ AT_DropExpression
Definition: parsenodes.h:2196
@ AT_AddIndex
Definition: parsenodes.h:2203
@ AT_EnableReplicaRule
Definition: parsenodes.h:2236
@ AT_DropConstraint
Definition: parsenodes.h:2211
@ AT_SetNotNull
Definition: parsenodes.h:2193
@ AT_ClusterOn
Definition: parsenodes.h:2216
@ AT_AddIdentity
Definition: parsenodes.h:2251
@ AT_ForceRowSecurity
Definition: parsenodes.h:2245
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2235
@ AT_SetAccessMethod
Definition: parsenodes.h:2221
@ AT_AlterColumnType
Definition: parsenodes.h:2213
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2250
@ AT_AddInherit
Definition: parsenodes.h:2238
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2207
@ AT_EnableTrig
Definition: parsenodes.h:2226
@ AT_DropColumn
Definition: parsenodes.h:2202
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2214
@ AT_DisableTrigAll
Definition: parsenodes.h:2231
@ AT_EnableRule
Definition: parsenodes.h:2234
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2246
@ AT_DetachPartition
Definition: parsenodes.h:2249
@ AT_SetStatistics
Definition: parsenodes.h:2197
@ AT_AttachPartition
Definition: parsenodes.h:2248
@ AT_AddConstraint
Definition: parsenodes.h:2205
@ AT_DropInherit
Definition: parsenodes.h:2239
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2227
@ AT_SetLogged
Definition: parsenodes.h:2218
@ AT_SetStorage
Definition: parsenodes.h:2200
@ AT_DisableRule
Definition: parsenodes.h:2237
@ AT_DisableRowSecurity
Definition: parsenodes.h:2244
@ AT_SetRelOptions
Definition: parsenodes.h:2223
@ AT_ChangeOwner
Definition: parsenodes.h:2215
@ AT_EnableTrigUser
Definition: parsenodes.h:2232
@ AT_SetExpression
Definition: parsenodes.h:2195
@ AT_ReAddConstraint
Definition: parsenodes.h:2206
@ AT_SetTableSpace
Definition: parsenodes.h:2222
@ AT_GenericOptions
Definition: parsenodes.h:2247
@ AT_ColumnDefault
Definition: parsenodes.h:2190
@ AT_CookedColumnDefault
Definition: parsenodes.h:2191
@ AT_AlterConstraint
Definition: parsenodes.h:2208
@ AT_EnableTrigAll
Definition: parsenodes.h:2230
@ AT_DropCluster
Definition: parsenodes.h:2217
@ AT_ValidateConstraint
Definition: parsenodes.h:2209
@ AT_AddColumn
Definition: parsenodes.h:2188
#define lfirst(lc)
Definition: pg_list.h:172
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2110
AlterTableType subtype
Definition: parsenodes.h:2267
ConstrType contype
Definition: parsenodes.h:2570
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_SetExpression, 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 4451 of file tablecmds.c.

4452 {
4453  Relation rel;
4454  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4455 
4456  rel = relation_open(relid, lockmode);
4457 
4459 
4460  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4461 }
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4496

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4363 of file tablecmds.c.

4364 {
4365  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4366  stmt->missing_ok ? RVR_MISSING_OK : 0,
4368  (void *) stmt);
4369 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:426
@ RVR_MISSING_OK
Definition: namespace.h:71
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:18193

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

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 15594 of file tablecmds.c.

15595 {
15596  List *relations = NIL;
15597  ListCell *l;
15598  ScanKeyData key[1];
15599  Relation rel;
15600  TableScanDesc scan;
15601  HeapTuple tuple;
15602  Oid orig_tablespaceoid;
15603  Oid new_tablespaceoid;
15604  List *role_oids = roleSpecsToIds(stmt->roles);
15605 
15606  /* Ensure we were not asked to move something we can't */
15607  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
15608  stmt->objtype != OBJECT_MATVIEW)
15609  ereport(ERROR,
15610  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15611  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
15612 
15613  /* Get the orig and new tablespace OIDs */
15614  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
15615  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
15616 
15617  /* Can't move shared relations in to or out of pg_global */
15618  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
15619  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
15620  new_tablespaceoid == GLOBALTABLESPACE_OID)
15621  ereport(ERROR,
15622  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15623  errmsg("cannot move relations in to or out of pg_global tablespace")));
15624 
15625  /*
15626  * Must have CREATE rights on the new tablespace, unless it is the
15627  * database default tablespace (which all users implicitly have CREATE
15628  * rights on).
15629  */
15630  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
15631  {
15632  AclResult aclresult;
15633 
15634  aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
15635  ACL_CREATE);
15636  if (aclresult != ACLCHECK_OK)
15637  aclcheck_error(aclresult, OBJECT_TABLESPACE,
15638  get_tablespace_name(new_tablespaceoid));
15639  }
15640 
15641  /*
15642  * Now that the checks are done, check if we should set either to
15643  * InvalidOid because it is our database's default tablespace.
15644  */
15645  if (orig_tablespaceoid == MyDatabaseTableSpace)
15646  orig_tablespaceoid = InvalidOid;
15647 
15648  if (new_tablespaceoid == MyDatabaseTableSpace)
15649  new_tablespaceoid = InvalidOid;
15650 
15651  /* no-op */
15652  if (orig_tablespaceoid == new_tablespaceoid)
15653  return new_tablespaceoid;
15654 
15655  /*
15656  * Walk the list of objects in the tablespace and move them. This will
15657  * only find objects in our database, of course.
15658  */
15659  ScanKeyInit(&key[0],
15660  Anum_pg_class_reltablespace,
15661  BTEqualStrategyNumber, F_OIDEQ,
15662  ObjectIdGetDatum(orig_tablespaceoid));
15663 
15664  rel = table_open(RelationRelationId, AccessShareLock);
15665  scan = table_beginscan_catalog(rel, 1, key);
15666  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
15667  {
15668  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
15669  Oid relOid = relForm->oid;
15670 
15671  /*
15672  * Do not move objects in pg_catalog as part of this, if an admin
15673  * really wishes to do so, they can issue the individual ALTER
15674  * commands directly.
15675  *
15676  * Also, explicitly avoid any shared tables, temp tables, or TOAST
15677  * (TOAST will be moved with the main table).
15678  */
15679  if (IsCatalogNamespace(relForm->relnamespace) ||
15680  relForm->relisshared ||
15681  isAnyTempNamespace(relForm->relnamespace) ||
15682  IsToastNamespace(relForm->relnamespace))
15683  continue;
15684 
15685  /* Only move the object type requested */
15686  if ((stmt->objtype == OBJECT_TABLE &&
15687  relForm->relkind != RELKIND_RELATION &&
15688  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
15689  (stmt->objtype == OBJECT_INDEX &&
15690  relForm->relkind != RELKIND_INDEX &&
15691  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
15692  (stmt->objtype == OBJECT_MATVIEW &&
15693  relForm->relkind != RELKIND_MATVIEW))
15694  continue;
15695 
15696  /* Check if we are only moving objects owned by certain roles */
15697  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
15698  continue;
15699 
15700  /*
15701  * Handle permissions-checking here since we are locking the tables
15702  * and also to avoid doing a bunch of work only to fail part-way. Note
15703  * that permissions will also be checked by AlterTableInternal().
15704  *
15705  * Caller must be considered an owner on the table to move it.
15706  */
15707  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
15709  NameStr(relForm->relname));
15710 
15711  if (stmt->nowait &&
15713  ereport(ERROR,
15714  (errcode(ERRCODE_OBJECT_IN_USE),
15715  errmsg("aborting because lock on relation \"%s.%s\" is not available",
15716  get_namespace_name(relForm->relnamespace),
15717  NameStr(relForm->relname))));
15718  else
15720 
15721  /* Add to our list of objects to move */
15722  relations = lappend_oid(relations, relOid);
15723  }
15724 
15725  table_endscan(scan);
15727 
15728  if (relations == NIL)
15729  ereport(NOTICE,
15730  (errcode(ERRCODE_NO_DATA_FOUND),
15731  errmsg("no matching relations in tablespace \"%s\" found",
15732  orig_tablespaceoid == InvalidOid ? "(database default)" :
15733  get_tablespace_name(orig_tablespaceoid))));
15734 
15735  /* Everything is locked, loop through and move all of the relations. */
15736  foreach(l, relations)
15737  {
15738  List *cmds = NIL;
15740 
15741  cmd->subtype = AT_SetTableSpace;
15742  cmd->name = stmt->new_tablespacename;
15743 
15744  cmds = lappend(cmds, cmd);
15745 
15747  /* OID is set by AlterTableInternal */
15748  AlterTableInternal(lfirst_oid(l), cmds, false);
15750  }
15751 
15752  return new_tablespaceoid;
15753 }
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:2701
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3878
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4132
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:1653
#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:92
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1086
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
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:1980
Oid GetUserId(void)
Definition: miscinit.c:515
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3672
#define makeNode(_type_)
Definition: nodes.h:155
ObjectType get_relkind_objtype(char relkind)
@ OBJECT_MATVIEW
Definition: parsenodes.h:2119
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2138
@ OBJECT_INDEX
Definition: parsenodes.h:2116
@ OBJECT_TABLE
Definition: parsenodes.h:2137
#define ACL_CREATE
Definition: parsenodes.h:85
#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:4451

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

17563 {
17564  Relation rel;
17565  Oid relid;
17566  Oid oldNspOid;
17567  Oid nspOid;
17568  RangeVar *newrv;
17569  ObjectAddresses *objsMoved;
17570  ObjectAddress myself;
17571 
17573  stmt->missing_ok ? RVR_MISSING_OK : 0,
17575  (void *) stmt);
17576 
17577  if (!OidIsValid(relid))
17578  {
17579  ereport(NOTICE,
17580  (errmsg("relation \"%s\" does not exist, skipping",
17581  stmt->relation->relname)));
17582  return InvalidObjectAddress;
17583  }
17584 
17585  rel = relation_open(relid, NoLock);
17586 
17587  oldNspOid = RelationGetNamespace(rel);
17588 
17589  /* If it's an owned sequence, disallow moving it by itself. */
17590  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
17591  {
17592  Oid tableId;
17593  int32 colId;
17594 
17595  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
17596  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
17597  ereport(ERROR,
17598  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17599  errmsg("cannot move an owned sequence into another schema"),
17600  errdetail("Sequence \"%s\" is linked to table \"%s\".",
17602  get_rel_name(tableId))));
17603  }
17604 
17605  /* Get and lock schema OID and check its permissions. */
17606  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
17607  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
17608 
17609  /* common checks on switching namespaces */
17610  CheckSetNamespace(oldNspOid, nspOid);
17611 
17612  objsMoved = new_object_addresses();
17613  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
17614  free_object_addresses(objsMoved);
17615 
17616  ObjectAddressSet(myself, RelationRelationId, relid);
17617 
17618  if (oldschema)
17619  *oldschema = oldNspOid;
17620 
17621  /* close rel, but keep lock until commit */
17622  relation_close(rel, NoLock);
17623 
17624  return myself;
17625 }
signed int int32
Definition: c.h:483
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2539
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2828
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int errdetail(const char *fmt,...)
Definition: elog.c:1208
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1905
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:724
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3444
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:17633

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

17635 {
17636  Relation classRel;
17637 
17638  Assert(objsMoved != NULL);
17639 
17640  /* OK, modify the pg_class row and pg_depend entry */
17641  classRel = table_open(RelationRelationId, RowExclusiveLock);
17642 
17643  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
17644  nspOid, true, objsMoved);
17645 
17646  /* Fix the table's row type too, if it has one */
17647  if (OidIsValid(rel->rd_rel->reltype))
17648  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
17649  nspOid, false, false, objsMoved);
17650 
17651  /* Fix other dependent stuff */
17652  if (rel->rd_rel->relkind == RELKIND_RELATION ||
17653  rel->rd_rel->relkind == RELKIND_MATVIEW ||
17654  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
17655  {
17656  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
17657  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
17658  objsMoved, AccessExclusiveLock);
17659  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
17660  false, objsMoved);
17661  }
17662 
17663  table_close(classRel, RowExclusiveLock);
17664 }
#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:17672
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:17787
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17742
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3981

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

18072 {
18073  ListCell *cur_item;
18074 
18075  foreach(cur_item, on_commits)
18076  {
18077  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
18078 
18079  if (!isCommit && oc->creating_subid == mySubid)
18080  {
18081  /* cur_item must be removed */
18083  pfree(oc);
18084  }
18085  else
18086  {
18087  /* cur_item must be preserved */
18088  if (oc->creating_subid == mySubid)
18089  oc->creating_subid = parentSubid;
18090  if (oc->deleting_subid == mySubid)
18091  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
18092  }
18093  }
18094 }
#define InvalidSubTransactionId
Definition: c.h:647
void pfree(void *pointer)
Definition: mcxt.c:1431
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
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 18038 of file tablecmds.c.

18039 {
18040  ListCell *cur_item;
18041 
18042  foreach(cur_item, on_commits)
18043  {
18044  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
18045 
18046  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
18048  {
18049  /* cur_item must be removed */
18051  pfree(oc);
18052  }
18053  else
18054  {
18055  /* cur_item must be preserved */
18058  }
18059  }
18060 }

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

14792 {
14793  Relation target_rel;
14794  Relation class_rel;
14795  HeapTuple tuple;
14796  Form_pg_class tuple_class;
14797 
14798  /*
14799  * Get exclusive lock till end of transaction on the target table. Use
14800  * relation_open so that we can work on indexes and sequences.
14801  */
14802  target_rel = relation_open(relationOid, lockmode);
14803 
14804  /* Get its pg_class tuple, too */
14805  class_rel = table_open(RelationRelationId, RowExclusiveLock);
14806 
14807  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
14808  if (!HeapTupleIsValid(tuple))
14809  elog(ERROR, "cache lookup failed for relation %u", relationOid);
14810  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
14811 
14812  /* Can we change the ownership of this tuple? */
14813  switch (tuple_class->relkind)
14814  {
14815  case RELKIND_RELATION:
14816  case RELKIND_VIEW:
14817  case RELKIND_MATVIEW:
14818  case RELKIND_FOREIGN_TABLE:
14819  case RELKIND_PARTITIONED_TABLE:
14820  /* ok to change owner */
14821  break;
14822  case RELKIND_INDEX:
14823  if (!recursing)
14824  {
14825  /*
14826  * Because ALTER INDEX OWNER used to be allowed, and in fact
14827  * is generated by old versions of pg_dump, we give a warning
14828  * and do nothing rather than erroring out. Also, to avoid
14829  * unnecessary chatter while restoring those old dumps, say
14830  * nothing at all if the command would be a no-op anyway.
14831  */
14832  if (tuple_class->relowner != newOwnerId)
14833  ereport(WARNING,
14834  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14835  errmsg("cannot change owner of index \"%s\"",
14836  NameStr(tuple_class->relname)),
14837  errhint("Change the ownership of the index's table instead.")));
14838  /* quick hack to exit via the no-op path */
14839  newOwnerId = tuple_class->relowner;
14840  }
14841  break;
14842  case RELKIND_PARTITIONED_INDEX:
14843  if (recursing)
14844  break;
14845  ereport(ERROR,
14846  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14847  errmsg("cannot change owner of index \"%s\"",
14848  NameStr(tuple_class->relname)),
14849  errhint("Change the ownership of the index's table instead.")));
14850  break;
14851  case RELKIND_SEQUENCE:
14852  if (!recursing &&
14853  tuple_class->relowner != newOwnerId)
14854  {
14855  /* if it's an owned sequence, disallow changing it by itself */
14856  Oid tableId;
14857  int32 colId;
14858 
14859  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
14860  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
14861  ereport(ERROR,
14862  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14863  errmsg("cannot change owner of sequence \"%s\"",
14864  NameStr(tuple_class->relname)),
14865  errdetail("Sequence \"%s\" is linked to table \"%s\".",
14866  NameStr(tuple_class->relname),
14867  get_rel_name(tableId))));
14868  }
14869  break;
14870  case RELKIND_COMPOSITE_TYPE:
14871  if (recursing)
14872  break;
14873  ereport(ERROR,
14874  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14875  errmsg("\"%s\" is a composite type",
14876  NameStr(tuple_class->relname)),
14877  /* translator: %s is an SQL ALTER command */
14878  errhint("Use %s instead.",
14879  "ALTER TYPE")));
14880  break;
14881  case RELKIND_TOASTVALUE:
14882  if (recursing)
14883  break;
14884  /* FALL THRU */
14885  default:
14886  ereport(ERROR,
14887  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14888  errmsg("cannot change owner of relation \"%s\"",
14889  NameStr(tuple_class->relname)),
14890  errdetail_relkind_not_supported(tuple_class->relkind)));
14891  }
14892 
14893  /*
14894  * If the new owner is the same as the existing owner, consider the
14895  * command to have succeeded. This is for dump restoration purposes.
14896  */
14897  if (tuple_class->relowner != newOwnerId)
14898  {
14899  Datum repl_val[Natts_pg_class];
14900  bool repl_null[Natts_pg_class];
14901  bool repl_repl[Natts_pg_class];
14902  Acl *newAcl;
14903  Datum aclDatum;
14904  bool isNull;
14905  HeapTuple newtuple;
14906 
14907  /* skip permission checks when recursing to index or toast table */
14908  if (!recursing)
14909  {
14910  /* Superusers can always do it */
14911  if (!superuser())
14912  {
14913  Oid namespaceOid = tuple_class->relnamespace;
14914  AclResult aclresult;
14915 
14916  /* Otherwise, must be owner of the existing object */
14917  if (!object_ownercheck(RelationRelationId, relationOid, GetUserId()))
14919  RelationGetRelationName(target_rel));
14920 
14921  /* Must be able to become new owner */
14922  check_can_set_role(GetUserId(), newOwnerId);
14923 
14924  /* New owner must have CREATE privilege on namespace */
14925  aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId,
14926  ACL_CREATE);
14927  if (aclresult != ACLCHECK_OK)
14928  aclcheck_error(aclresult, OBJECT_SCHEMA,
14929  get_namespace_name(namespaceOid));
14930  }
14931  }
14932 
14933  memset(repl_null, false, sizeof(repl_null));
14934  memset(repl_repl, false, sizeof(repl_repl));
14935 
14936  repl_repl[Anum_pg_class_relowner - 1] = true;
14937  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
14938 
14939  /*
14940  * Determine the modified ACL for the new owner. This is only
14941  * necessary when the ACL is non-null.
14942  */
14943  aclDatum = SysCacheGetAttr(RELOID, tuple,
14944  Anum_pg_class_relacl,
14945  &isNull);
14946  if (!isNull)
14947  {
14948  newAcl = aclnewowner(DatumGetAclP(aclDatum),
14949  tuple_class->relowner, newOwnerId);
14950  repl_repl[Anum_pg_class_relacl - 1] = true;
14951  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
14952  }
14953 
14954  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
14955 
14956  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
14957 
14958  heap_freetuple(newtuple);
14959 
14960  /*
14961  * We must similarly update any per-column ACLs to reflect the new
14962  * owner; for neatness reasons that's split out as a subroutine.
14963  */
14964  change_owner_fix_column_acls(relationOid,
14965  tuple_class->relowner,
14966  newOwnerId);
14967 
14968  /*
14969  * Update owner dependency reference, if any. A composite type has
14970  * none, because it's tracked for the pg_type entry instead of here;
14971  * indexes and TOAST tables don't have their own entries either.
14972  */
14973  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
14974  tuple_class->relkind != RELKIND_INDEX &&
14975  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
14976  tuple_class->relkind != RELKIND_TOASTVALUE)
14977  changeDependencyOnOwner(RelationRelationId, relationOid,
14978  newOwnerId);
14979 
14980  /*
14981  * Also change the ownership of the table's row type, if it has one
14982  */
14983  if (OidIsValid(tuple_class->reltype))
14984  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
14985 
14986  /*
14987  * If we are operating on a table or materialized view, also change
14988  * the ownership of any indexes and sequences that belong to the
14989  * relation, as well as its toast table (if it has one).
14990  */
14991  if (tuple_class->relkind == RELKIND_RELATION ||
14992  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
14993  tuple_class->relkind == RELKIND_MATVIEW ||
14994  tuple_class->relkind == RELKIND_TOASTVALUE)
14995  {
14996  List *index_oid_list;
14997  ListCell *i;
14998 
14999  /* Find all the indexes belonging to this relation */
15000  index_oid_list = RelationGetIndexList(target_rel);
15001 
15002  /* For each index, recursively change its ownership */
15003  foreach(i, index_oid_list)
15004  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
15005 
15006  list_free(index_oid_list);
15007  }
15008 
15009  /* If it has a toast table, recurse to change its ownership */
15010  if (tuple_class->reltoastrelid != InvalidOid)
15011  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
15012  true, lockmode);
15013 
15014  /* If it has dependent sequences, recurse to change them too */
15015  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
15016  }
15017 
15018  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
15019 
15020  ReleaseSysCache(tuple);
15021  table_close(class_rel, RowExclusiveLock);
15022  relation_close(target_rel, NoLock);
15023 }
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:5117
#define DatumGetAclP(X)
Definition: acl.h:120
int errhint(const char *fmt,...)
Definition: elog.c:1322
#define WARNING
Definition: elog.h:36
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
int i
Definition: isn.c:73
void list_free(List *list)
Definition: list.c:1546
@ OBJECT_SCHEMA
Definition: parsenodes.h:2132
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:4755
bool superuser(void)
Definition: superuser.c:46
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:267
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:219
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:480
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:14791
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:15097
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:15032
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3838

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

◆ BuildDescForRelation()

TupleDesc BuildDescForRelation ( const List columns)

Definition at line 1296 of file tablecmds.c.

1297 {
1298  int natts;
1300  ListCell *l;
1301  TupleDesc desc;
1302  bool has_not_null;
1303  char *attname;
1304  Oid atttypid;
1305  int32 atttypmod;
1306  Oid attcollation;
1307  int attdim;
1308 
1309  /*
1310  * allocate a new tuple descriptor
1311  */
1312  natts = list_length(columns);
1313  desc = CreateTemplateTupleDesc(natts);
1314  has_not_null = false;
1315 
1316  attnum = 0;
1317 
1318  foreach(l, columns)
1319  {
1320  ColumnDef *entry = lfirst(l);
1321  AclResult aclresult;
1322  Form_pg_attribute att;
1323 
1324  /*
1325  * for each entry in the list, get the name and type information from
1326  * the list and have TupleDescInitEntry fill in the attribute
1327  * information we need.
1328  */
1329  attnum++;
1330 
1331  attname = entry->colname;
1332  typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
1333 
1334  aclresult = object_aclcheck(TypeRelationId, atttypid, GetUserId(), ACL_USAGE);
1335  if (aclresult != ACLCHECK_OK)
1336  aclcheck_error_type(aclresult, atttypid);
1337 
1338  attcollation = GetColumnDefCollation(NULL, entry, atttypid);
1339  attdim = list_length(entry->typeName->arrayBounds);
1340  if (attdim > PG_INT16_MAX)
1341  ereport(ERROR,
1342  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1343  errmsg("too many array dimensions"));
1344 
1345  if (entry->typeName->setof)
1346  ereport(ERROR,
1347  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
1348  errmsg("column \"%s\" cannot be declared SETOF",
1349  attname)));
1350 
1352  atttypid, atttypmod, attdim);
1353  att = TupleDescAttr(desc, attnum - 1);
1354 
1355  /* Override TupleDescInitEntry's settings as requested */
1356  TupleDescInitEntryCollation(desc, attnum, attcollation);
1357 
1358  /* Fill in additional stuff not handled by TupleDescInitEntry */
1359  att->attnotnull = entry->is_not_null;
1360  has_not_null |= entry->is_not_null;
1361  att->attislocal = entry->is_local;
1362  att->attinhcount = entry->inhcount;
1363  att->attidentity = entry->identity;
1364  att->attgenerated = entry->generated;
1365  att->attcompression = GetAttributeCompression(att->atttypid, entry->compression);
1366  if (entry->storage)
1367  att->attstorage = entry->storage;
1368  else if (entry->storage_name)
1369  att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name);
1370  }
1371 
1372  if (has_not_null)
1373  {
1374  TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
1375 
1376  constr->has_not_null = true;
1377  constr->has_generated_stored = false;
1378  constr->defval = NULL;
1379  constr->missing = NULL;
1380  constr->num_defval = 0;
1381  constr->check = NULL;
1382  constr->num_check = 0;
1383  desc->constr = constr;
1384  }
1385  else
1386  {
1387  desc->constr = NULL;
1388  }
1389 
1390  return desc;
1391 }
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3020
int16 AttrNumber
Definition: attnum.h:21
#define PG_INT16_MAX
Definition: c.h:575
void * palloc0(Size size)
Definition: mcxt.c:1232
void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, Oid *typeid_p, int32 *typmod_p)
Definition: parse_type.c:310
Oid GetColumnDefCollation(ParseState *pstate, const ColumnDef *coldef, Oid typeOid)
Definition: parse_type.c:540
#define ACL_USAGE
Definition: parsenodes.h:84
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
static int list_length(const List *l)
Definition: pg_list.h:152
bool is_not_null
Definition: parsenodes.h:718
char identity
Definition: parsenodes.h:724
char * storage_name
Definition: parsenodes.h:721
int inhcount
Definition: parsenodes.h:716
char * colname
Definition: parsenodes.h:713
TypeName * typeName
Definition: parsenodes.h:714
char generated
Definition: parsenodes.h:727
char storage
Definition: parsenodes.h:720
bool is_local
Definition: parsenodes.h:717
char * compression
Definition: parsenodes.h:715
bool has_not_null
Definition: tupdesc.h:44
AttrDefault * defval
Definition: tupdesc.h:39
bool has_generated_stored
Definition: tupdesc.h:45
struct AttrMissing * missing
Definition: tupdesc.h:41
ConstrCheck * check
Definition: tupdesc.h:40
uint16 num_defval
Definition: tupdesc.h:42
uint16 num_check
Definition: tupdesc.h:43
TupleConstr * constr
Definition: tupdesc.h:85
bool setof
Definition: parsenodes.h:260
List * arrayBounds
Definition: parsenodes.h:264
static char GetAttributeCompression(Oid atttypid, const char *compression)
Definition: tablecmds.c:20529
static char GetAttributeStorage(Oid atttypid, const char *storagemode)
Definition: tablecmds.c:20567
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67
void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid)
Definition: tupdesc.c:785
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:603
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, TypeName::arrayBounds, attname, attnum, TupleConstr::check, ColumnDef::colname, ColumnDef::compression, TupleDescData::constr, CreateTemplateTupleDesc(), TupleConstr::defval, ereport, errcode(), errmsg(), ERROR, ColumnDef::generated, GetAttributeCompression(), GetAttributeStorage(), GetColumnDefCollation(), GetUserId(), TupleConstr::has_generated_stored, TupleConstr::has_not_null, ColumnDef::identity, ColumnDef::inhcount, ColumnDef::is_local, ColumnDef::is_not_null, lfirst, list_length(), TupleConstr::missing, TupleConstr::num_check, TupleConstr::num_defval, object_aclcheck(), palloc0(), PG_INT16_MAX, TypeName::setof, ColumnDef::storage, ColumnDef::storage_name, TupleDescAttr, TupleDescInitEntry(), TupleDescInitEntryCollation(), ColumnDef::typeName, and typenameTypeIdAndMod().

Referenced by ATExecAddColumn(), DefineRelation(), and DefineVirtualRelation().

◆ check_of_type()

void check_of_type ( HeapTuple  typetuple)

Definition at line 6962 of file tablecmds.c.

6963 {
6964  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
6965  bool typeOk = false;
6966 
6967  if (typ->typtype == TYPTYPE_COMPOSITE)
6968  {
6969  Relation typeRelation;
6970 
6971  Assert(OidIsValid(typ->typrelid));
6972  typeRelation = relation_open(typ->typrelid, AccessShareLock);
6973  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6974 
6975  /*
6976  * Close the parent rel, but keep our AccessShareLock on it until xact
6977  * commit. That will prevent someone else from deleting or ALTERing
6978  * the type before the typed table creation/conversion commits.
6979  */
6980  relation_close(typeRelation, NoLock);
6981  }
6982  if (!typeOk)
6983  ereport(ERROR,
6984  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6985  errmsg("type %s is not a composite type",
6986  format_type_be(typ->oid))));
6987 }
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 3618 of file tablecmds.c.

3619 {
3620  Oid oldTableSpaceId;
3621 
3622  /*
3623  * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3624  * stored as 0.
3625  */
3626  oldTableSpaceId = rel->rd_rel->reltablespace;
3627  if (newTableSpaceId == oldTableSpaceId ||
3628  (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3629  return false;
3630 
3631  /*
3632  * We cannot support moving mapped relations into different tablespaces.
3633  * (In particular this eliminates all shared catalogs.)
3634  */
3635  if (RelationIsMapped(rel))
3636  ereport(ERROR,
3637  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3638  errmsg("cannot move system relation \"%s\"",
3639  RelationGetRelationName(rel))));
3640 
3641  /* Cannot move a non-shared relation into pg_global */
3642  if (newTableSpaceId == GLOBALTABLESPACE_OID)
3643  ereport(ERROR,
3644  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3645  errmsg("only shared relations can be placed in pg_global tablespace")));
3646 
3647  /*
3648  * Do not allow moving temp tables of other backends ... their local
3649  * buffer manager is not going to cope.
3650  */
3651  if (RELATION_IS_OTHER_TEMP(rel))
3652  ereport(ERROR,
3653  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3654  errmsg("cannot move temporary tables of other sessions")));
3655 
3656  return true;
3657 }
#define RelationIsMapped(relation)
Definition: rel.h:553
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:657

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

4336 {
4337  int expected_refcnt;
4338 
4339  expected_refcnt = rel->rd_isnailed ? 2 : 1;
4340  if (rel->rd_refcnt != expected_refcnt)
4341  ereport(ERROR,
4342  (errcode(ERRCODE_OBJECT_IN_USE),
4343  /* translator: first %s is a SQL command, eg ALTER TABLE */
4344  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
4345  stmt, RelationGetRelationName(rel))));
4346 
4347  if (rel->rd_rel->relkind != RELKIND_INDEX &&
4348  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
4350  ereport(ERROR,
4351  (errcode(ERRCODE_OBJECT_IN_USE),
4352  /* translator: first %s is a SQL command, eg ALTER TABLE */
4353  errmsg("cannot %s \"%s\" because it has pending trigger events",
4354  stmt, RelationGetRelationName(rel))));
4355 }
int rd_refcnt
Definition: rel.h:59
bool rd_isnailed
Definition: rel.h:62
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5981

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

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

1797 {
1798  List *rels = NIL;
1799  List *relids = NIL;
1800  List *relids_logged = NIL;
1801  ListCell *cell;
1802 
1803  /*
1804  * Open, exclusive-lock, and check all the explicitly-specified relations
1805  */
1806  foreach(cell, stmt->relations)
1807  {
1808  RangeVar *rv = lfirst(cell);
1809  Relation rel;
1810  bool recurse = rv->inh;
1811  Oid myrelid;
1812  LOCKMODE lockmode = AccessExclusiveLock;
1813 
1814  myrelid = RangeVarGetRelidExtended(rv, lockmode,
1816  NULL);
1817 
1818  /* don't throw error for "TRUNCATE foo, foo" */
1819  if (list_member_oid(relids, myrelid))
1820  continue;
1821 
1822  /* open the relation, we already hold a lock on it */
1823  rel = table_open(myrelid, NoLock);
1824 
1825  /*
1826  * RangeVarGetRelidExtended() has done most checks with its callback,
1827  * but other checks with the now-opened Relation remain.
1828  */
1830 
1831  rels = lappend(rels, rel);
1832  relids = lappend_oid(relids, myrelid);
1833 
1834  /* Log this relation only if needed for logical decoding */
1835  if (RelationIsLogicallyLogged(rel))
1836  relids_logged = lappend_oid(relids_logged, myrelid);
1837 
1838  if (recurse)
1839  {
1840  ListCell *child;
1841  List *children;
1842 
1843  children = find_all_inheritors(myrelid, lockmode, NULL);
1844 
1845  foreach(child, children)
1846  {
1847  Oid childrelid = lfirst_oid(child);
1848 
1849  if (list_member_oid(relids, childrelid))
1850  continue;
1851 
1852  /* find_all_inheritors already got lock */
1853  rel = table_open(childrelid, NoLock);
1854 
1855  /*
1856  * It is possible that the parent table has children that are
1857  * temp tables of other backends. We cannot safely access
1858  * such tables (because of buffering issues), and the best
1859  * thing to do is to silently ignore them. Note that this
1860  * check is the same as one of the checks done in
1861  * truncate_check_activity() called below, still it is kept
1862  * here for simplicity.
1863  */
1864  if (RELATION_IS_OTHER_TEMP(rel))
1865  {
1866  table_close(rel, lockmode);
1867  continue;
1868  }
1869 
1870  /*
1871  * Inherited TRUNCATE commands perform access permission
1872  * checks on the parent table only. So we skip checking the
1873  * children's permissions and don't call
1874  * truncate_check_perms() here.
1875  */
1878 
1879  rels = lappend(rels, rel);
1880  relids = lappend_oid(relids, childrelid);
1881 
1882  /* Log this relation only if needed for logical decoding */
1883  if (RelationIsLogicallyLogged(rel))
1884  relids_logged = lappend_oid(relids_logged, childrelid);
1885  }
1886  }
1887  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1888  ereport(ERROR,
1889  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1890  errmsg("cannot truncate only a partitioned table"),
1891  errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1892  }
1893 
1894  ExecuteTruncateGuts(rels, relids, relids_logged,
1895  stmt->behavior, stmt->restart_seqs, false);
1896 
1897  /* And close the rels */
1898  foreach(cell, rels)
1899  {
1900  Relation rel = (Relation) lfirst(cell);
1901 
1902  table_close(rel, NoLock);
1903  }
1904 }
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:256
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:700
struct RelationData * Relation
Definition: relcache.h:27
bool inh
Definition: primnodes.h:85
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2373
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2307
static void RangeVarCallbackForTruncate(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:18137
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs, bool run_as_table_owner)
Definition: tablecmds.c:1920

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

1925 {
1926  List *rels;
1927  List *seq_relids = NIL;
1928  HTAB *ft_htab = NULL;
1929  EState *estate;
1930  ResultRelInfo *resultRelInfos;
1931  ResultRelInfo *resultRelInfo;
1932  SubTransactionId mySubid;
1933  ListCell *cell;
1934  Oid *logrelids;
1935 
1936  /*
1937  * Check the explicitly-specified relations.
1938  *
1939  * In CASCADE mode, suck in all referencing relations as well. This
1940  * requires multiple iterations to find indirectly-dependent relations. At
1941  * each phase, we need to exclusive-lock new rels before looking for their
1942  * dependencies, else we might miss something. Also, we check each rel as
1943  * soon as we open it, to avoid a faux pas such as holding lock for a long
1944  * time on a rel we have no permissions for.
1945  */
1946  rels = list_copy(explicit_rels);
1947  if (behavior == DROP_CASCADE)
1948  {
1949  for (;;)
1950  {
1951  List *newrelids;
1952 
1953  newrelids = heap_truncate_find_FKs(relids);
1954  if (newrelids == NIL)
1955  break; /* nothing else to add */
1956 
1957  foreach(cell, newrelids)
1958  {
1959  Oid relid = lfirst_oid(cell);
1960  Relation rel;
1961 
1962  rel = table_open(relid, AccessExclusiveLock);
1963  ereport(NOTICE,
1964  (errmsg("truncate cascades to table \"%s\"",
1965  RelationGetRelationName(rel))));
1966  truncate_check_rel(relid, rel->rd_rel);
1967  truncate_check_perms(relid, rel->rd_rel);
1969  rels = lappend(rels, rel);
1970  relids = lappend_oid(relids, relid);
1971 
1972  /* Log this relation only if needed for logical decoding */
1973  if (RelationIsLogicallyLogged(rel))
1974  relids_logged = lappend_oid(relids_logged, relid);
1975  }
1976  }
1977  }
1978 
1979  /*
1980  * Check foreign key references. In CASCADE mode, this should be
1981  * unnecessary since we just pulled in all the references; but as a
1982  * cross-check, do it anyway if in an Assert-enabled build.
1983  */
1984 #ifdef USE_ASSERT_CHECKING
1985  heap_truncate_check_FKs(rels, false);
1986 #else
1987  if (behavior == DROP_RESTRICT)
1988  heap_truncate_check_FKs(rels, false);
1989 #endif
1990 
1991  /*
1992  * If we are asked to restart sequences, find all the sequences, lock them
1993  * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1994  * We want to do this early since it's pointless to do all the truncation
1995  * work only to fail on sequence permissions.
1996  */
1997  if (restart_seqs)
1998  {
1999  foreach(cell, rels)
2000  {
2001  Relation rel = (Relation) lfirst(cell);
2002  List *seqlist = getOwnedSequences(RelationGetRelid(rel));
2003  ListCell *seqcell;
2004 
2005  foreach(seqcell, seqlist)
2006  {
2007  Oid seq_relid = lfirst_oid(seqcell);
2008  Relation seq_rel;
2009 
2010  seq_rel = relation_open(seq_relid, AccessExclusiveLock);
2011 
2012  /* This check must match AlterSequence! */
2013  if (!object_ownercheck(RelationRelationId, seq_relid, GetUserId()))
2015  RelationGetRelationName(seq_rel));
2016 
2017  seq_relids = lappend_oid(seq_relids, seq_relid);
2018 
2019  relation_close(seq_rel, NoLock);
2020  }
2021  }
2022  }
2023 
2024  /* Prepare to catch AFTER triggers. */
2026 
2027  /*
2028  * To fire triggers, we'll need an EState as well as a ResultRelInfo for
2029  * each relation. We don't need to call ExecOpenIndices, though.
2030  *
2031  * We put the ResultRelInfos in the es_opened_result_relations list, even
2032  * though we don't have a range table and don't populate the
2033  * es_result_relations array. That's a bit bogus, but it's enough to make
2034  * ExecGetTriggerResultRel() find them.
2035  */
2036  estate = CreateExecutorState();
2037  resultRelInfos = (ResultRelInfo *)
2038  palloc(list_length(rels) * sizeof(ResultRelInfo));
2039  resultRelInfo = resultRelInfos;
2040  foreach(cell, rels)
2041  {
2042  Relation rel = (Relation) lfirst(cell);
2043 
2044  InitResultRelInfo(resultRelInfo,
2045  rel,
2046  0, /* dummy rangetable index */
2047  NULL,
2048  0);
2049  estate->es_opened_result_relations =
2050  lappend(estate->es_opened_result_relations, resultRelInfo);
2051  resultRelInfo++;
2052  }
2053 
2054  /*
2055  * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
2056  * truncating (this is because one of them might throw an error). Also, if
2057  * we were to allow them to prevent statement execution, that would need
2058  * to be handled here.
2059  */
2060  resultRelInfo = resultRelInfos;
2061  foreach(cell, rels)
2062  {
2063  UserContext ucxt;
2064 
2065  if (run_as_table_owner)
2066  SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2067  &ucxt);
2068  ExecBSTruncateTriggers(estate, resultRelInfo);
2069  if (run_as_table_owner)
2070  RestoreUserContext(&ucxt);
2071  resultRelInfo++;
2072  }
2073 
2074  /*
2075  * OK, truncate each table.
2076  */
2077  mySubid = GetCurrentSubTransactionId();
2078 
2079  foreach(cell, rels)
2080  {
2081  Relation rel = (Relation) lfirst(cell);
2082 
2083  /* Skip partitioned tables as there is nothing to do */
2084  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2085  continue;
2086 
2087  /*
2088  * Build the lists of foreign tables belonging to each foreign server
2089  * and pass each list to the foreign data wrapper's callback function,
2090  * so that each server can truncate its all foreign tables in bulk.
2091  * Each list is saved as a single entry in a hash table that uses the
2092  * server OID as lookup key.
2093  */
2094  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2095  {
2097  bool found;
2098  ForeignTruncateInfo *ft_info;
2099 
2100  /* First time through, initialize hashtable for foreign tables */
2101  if (!ft_htab)
2102  {
2103  HASHCTL hctl;
2104 
2105  memset(&hctl, 0, sizeof(HASHCTL));
2106  hctl.keysize = sizeof(Oid);
2107  hctl.entrysize = sizeof(ForeignTruncateInfo);
2108  hctl.hcxt = CurrentMemoryContext;
2109 
2110  ft_htab = hash_create("TRUNCATE for Foreign Tables",
2111  32, /* start small and extend */
2112  &hctl,
2114  }
2115 
2116  /* Find or create cached entry for the foreign table */
2117  ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
2118  if (!found)
2119  ft_info->rels = NIL;
2120 
2121  /*
2122  * Save the foreign table in the entry of the server that the
2123  * foreign table belongs to.
2124  */
2125  ft_info->rels = lappend(ft_info->rels, rel);
2126  continue;
2127  }
2128 
2129  /*
2130  * Normally, we need a transaction-safe truncation here. However, if
2131  * the table was either created in the current (sub)transaction or has
2132  * a new relfilenumber in the current (sub)transaction, then we can
2133  * just truncate it in-place, because a rollback would cause the whole
2134  * table or the current physical file to be thrown away anyway.
2135  */
2136  if (rel->rd_createSubid == mySubid ||
2137  rel->rd_newRelfilelocatorSubid == mySubid)
2138  {
2139  /* Immediate, non-rollbackable truncation is OK */
2140  heap_truncate_one_rel(rel);
2141  }
2142  else
2143  {
2144  Oid heap_relid;
2145  Oid toast_relid;
2146  ReindexParams reindex_params = {0};
2147 
2148  /*
2149  * This effectively deletes all rows in the table, and may be done
2150  * in a serializable transaction. In that case we must record a
2151  * rw-conflict in to this transaction from each transaction
2152  * holding a predicate lock on the table.
2153  */
2155 
2156  /*
2157  * Need the full transaction-safe pushups.
2158  *
2159  * Create a new empty storage file for the relation, and assign it
2160  * as the relfilenumber value. The old storage file is scheduled
2161  * for deletion at commit.
2162  */
2163  RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
2164 
2165  heap_relid = RelationGetRelid(rel);
2166 
2167  /*
2168  * The same for the toast table, if any.
2169  */
2170  toast_relid = rel->rd_rel->reltoastrelid;
2171  if (OidIsValid(toast_relid))
2172  {
2173  Relation toastrel = relation_open(toast_relid,
2175 
2176  RelationSetNewRelfilenumber(toastrel,
2177  toastrel->rd_rel->relpersistence);
2178  table_close(toastrel, NoLock);
2179  }
2180 
2181  /*
2182  * Reconstruct the indexes to match, and we're done.
2183  */
2184  reindex_relation(NULL, heap_relid, REINDEX_REL_PROCESS_TOAST,
2185  &reindex_params);
2186  }
2187 
2188  pgstat_count_truncate(rel);
2189  }
2190 
2191  /* Now go through the hash table, and truncate foreign tables */
2192  if (ft_htab)
2193  {
2194  ForeignTruncateInfo *ft_info;
2195  HASH_SEQ_STATUS seq;
2196 
2197  hash_seq_init(&seq, ft_htab);
2198 
2199  PG_TRY();
2200  {
2201  while ((ft_info = hash_seq_search(&seq)) != NULL)
2202  {
2203  FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2204 
2205  /* truncate_check_rel() has checked that already */
2206  Assert(routine->ExecForeignTruncate != NULL);
2207 
2208  routine->ExecForeignTruncate(ft_info->rels,
2209  behavior,
2210  restart_seqs);
2211  }
2212  }
2213  PG_FINALLY();
2214  {
2215  hash_destroy(ft_htab);
2216  }
2217  PG_END_TRY();
2218  }
2219 
2220  /*
2221  * Restart owned sequences if we were asked to.
2222  */
2223  foreach(cell, seq_relids)
2224  {
2225  Oid seq_relid = lfirst_oid(cell);
2226 
2227  ResetSequence(seq_relid);
2228  }
2229 
2230  /*
2231  * Write a WAL record to allow this set of actions to be logically
2232  * decoded.
2233  *
2234  * Assemble an array of relids so we can write a single WAL record for the
2235  * whole action.
2236  */
2237  if (relids_logged != NIL)
2238  {
2239  xl_heap_truncate xlrec;
2240  int i = 0;
2241 
2242  /* should only get here if wal_level >= logical */
2244 
2245  logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
2246  foreach(cell, relids_logged)
2247  logrelids[i++] = lfirst_oid(cell);
2248 
2249  xlrec.dbId = MyDatabaseId;
2250  xlrec.nrelids = list_length(relids_logged);
2251  xlrec.flags = 0;
2252  if (behavior == DROP_CASCADE)
2253  xlrec.flags |= XLH_TRUNCATE_CASCADE;
2254  if (restart_seqs)
2256 
2257  XLogBeginInsert();
2258  XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
2259  XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
2260 
2262 
2263  (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
2264  }
2265 
2266  /*
2267  * Process all AFTER STATEMENT TRUNCATE triggers.
2268  */
2269  resultRelInfo = resultRelInfos;
2270  foreach(cell, rels)
2271  {
2272  UserContext ucxt;
2273 
2274  if (run_as_table_owner)
2275  SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2276  &ucxt);
2277  ExecASTruncateTriggers(estate, resultRelInfo);
2278  if (run_as_table_owner)
2279  RestoreUserContext(&ucxt);
2280  resultRelInfo++;
2281  }
2282 
2283  /* Handle queued AFTER triggers */
2284  AfterTriggerEndQuery(estate);
2285 
2286  /* We can clean up the EState now */
2287  FreeExecutorState(estate);
2288 
2289  /*
2290  * Close any rels opened by CASCADE (can't do this while EState still
2291  * holds refs)
2292  */
2293  rels = list_difference_ptr(rels, explicit_rels);
2294  foreach(cell, rels)
2295  {
2296  Relation rel = (Relation) lfirst(cell);
2297 
2298  table_close(rel, NoLock);
2299  }
2300 }
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:346
FdwRoutine * GetFdwRoutineByServerId(Oid serverid)
Definition: foreign.c:368
Oid MyDatabaseId
Definition: globals.c:90
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3519
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3424
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3380
#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(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition: index.c:3913
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:158
List * list_difference_ptr(const List *list1, const List *list2)
Definition: list.c:1263
List * list_copy(const List *oldlist)
Definition: list.c:1573
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
@ DROP_CASCADE
Definition: parsenodes.h:2170
@ DROP_RESTRICT
Definition: parsenodes.h:2169
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2133
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:935
void pgstat_count_truncate(Relation rel)
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4389
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition: relcache.c:3725
void ResetSequence(Oid seq_relid)
Definition: sequence.c:261
List * es_opened_result_relations
Definition: execnodes.h:643
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:456
struct ForeignTruncateInfo ForeignTruncateInfo
static void truncate_check_perms(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2355
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3229
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3276
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:5045
void AfterTriggerBeginQuery(void)
Definition: trigger.c:5025
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:124
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:152
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:365
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:475
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:457
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 6755 of file tablecmds.c.

6757 {
6758  Relation depRel;
6759  ScanKeyData key[2];
6760  SysScanDesc depScan;
6761  HeapTuple depTup;
6762 
6763  /* since this function recurses, it could be driven to stack overflow */
6765 
6766  /*
6767  * We scan pg_depend to find those things that depend on the given type.
6768  * (We assume we can ignore refobjsubid for a type.)
6769  */
6770  depRel = table_open(DependRelationId, AccessShareLock);
6771 
6772  ScanKeyInit(&key[0],
6773  Anum_pg_depend_refclassid,
6774  BTEqualStrategyNumber, F_OIDEQ,
6775  ObjectIdGetDatum(TypeRelationId));
6776  ScanKeyInit(&key[1],
6777  Anum_pg_depend_refobjid,
6778  BTEqualStrategyNumber, F_OIDEQ,
6779  ObjectIdGetDatum(typeOid));
6780 
6781  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6782  NULL, 2, key);
6783 
6784  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6785  {
6786  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6787  Relation rel;
6788  TupleDesc tupleDesc;
6789  Form_pg_attribute att;
6790 
6791  /* Check for directly dependent types */
6792  if (pg_depend->classid == TypeRelationId)
6793  {
6794  /*
6795  * This must be an array, domain, or range containing the given
6796  * type, so recursively check for uses of this type. Note that
6797  * any error message will mention the original type not the
6798  * container; this is intentional.
6799  */
6800  find_composite_type_dependencies(pg_depend->objid,
6801  origRelation, origTypeName);
6802  continue;
6803  }
6804 
6805  /* Else, ignore dependees that aren't relations */
6806  if (pg_depend->classid != RelationRelationId)
6807  continue;
6808 
6809  rel = relation_open(pg_depend->objid, AccessShareLock);
6810  tupleDesc = RelationGetDescr(rel);
6811 
6812  /*
6813  * If objsubid identifies a specific column, refer to that in error
6814  * messages. Otherwise, search to see if there's a user column of the
6815  * type. (We assume system columns are never of interesting types.)
6816  * The search is needed because an index containing an expression
6817  * column of the target type will just be recorded as a whole-relation
6818  * dependency. If we do not find a column of the type, the dependency
6819  * must indicate that the type is transiently referenced in an index
6820  * expression but not stored on disk, which we assume is OK, just as
6821  * we do for references in views. (It could also be that the target
6822  * type is embedded in some container type that is stored in an index
6823  * column, but the previous recursion should catch such cases.)
6824  */
6825  if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
6826  att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
6827  else
6828  {
6829  att = NULL;
6830  for (int attno = 1; attno <= tupleDesc->natts; attno++)
6831  {
6832  att = TupleDescAttr(tupleDesc, attno - 1);
6833  if (att->atttypid == typeOid && !att->attisdropped)
6834  break;
6835  att = NULL;
6836  }
6837  if (att == NULL)
6838  {
6839  /* No such column, so assume OK */
6841  continue;
6842  }
6843  }
6844 
6845  /*
6846  * We definitely should reject if the relation has storage. If it's
6847  * partitioned, then perhaps we don't have to reject: if there are
6848  * partitions then we'll fail when we find one, else there is no
6849  * stored data to worry about. However, it's possible that the type
6850  * change would affect conclusions about whether the type is sortable
6851  * or hashable and thus (if it's a partitioning column) break the
6852  * partitioning rule. For now, reject for partitioned rels too.
6853  */
6854  if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
6855  RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
6856  {
6857  if (origTypeName)
6858  ereport(ERROR,
6859  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6860  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6861  origTypeName,
6863  NameStr(att->attname))));
6864  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6865  ereport(ERROR,
6866  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6867  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6868  RelationGetRelationName(origRelation),
6870  NameStr(att->attname))));
6871  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
6872  ereport(ERROR,
6873  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6874  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
6875  RelationGetRelationName(origRelation),
6877  NameStr(att->attname))));
6878  else
6879  ereport(ERROR,
6880  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6881  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
6882  RelationGetRelationName(origRelation),
6884  NameStr(att->attname))));
6885  }
6886  else if (OidIsValid(rel->rd_rel->reltype))
6887  {
6888  /*
6889  * A view or composite type itself isn't a problem, but we must
6890  * recursively check for indirect dependencies via its rowtype.
6891  */
6893  origRelation, origTypeName);
6894  }
6895 
6897  }
6898 
6899  systable_endscan(depScan);
6900 
6902 }
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:6755

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

18652 {
18653  List *existConstraint = NIL;
18654  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
18655  int i;
18656 
18657  if (constr && constr->has_not_null)
18658  {
18659  int natts = scanrel->rd_att->natts;
18660 
18661  for (i = 1; i <= natts; i++)
18662  {
18663  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
18664 
18665  if (att->attnotnull && !att->attisdropped)
18666  {
18667  NullTest *ntest = makeNode(NullTest);
18668 
18669  ntest->arg = (Expr *) makeVar(1,
18670  i,
18671  att->atttypid,
18672  att->atttypmod,
18673  att->attcollation,
18674  0);
18675  ntest->nulltesttype = IS_NOT_NULL;
18676 
18677  /*
18678  * argisrow=false is correct even for a composite column,
18679  * because attnotnull does not represent a SQL-spec IS NOT
18680  * NULL test in such a case, just IS DISTINCT FROM NULL.
18681  */
18682  ntest->argisrow = false;
18683  ntest->location = -1;
18684  existConstraint = lappend(existConstraint, ntest);
18685  }
18686  }
18687  }
18688 
18689  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
18690 }
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
@ IS_NOT_NULL
Definition: primnodes.h:1694
NullTestType nulltesttype
Definition: primnodes.h:1701
int location
Definition: primnodes.h:1704
Expr * arg
Definition: primnodes.h:1700
TupleDesc rd_att
Definition: rel.h:112
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:18703

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

17932 {
17933  ListCell *l;
17934  List *oids_to_truncate = NIL;
17935  List *oids_to_drop = NIL;
17936 
17937  foreach(l, on_commits)
17938  {
17939  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
17940 
17941  /* Ignore entry if already dropped in this xact */
17943  continue;
17944 
17945  switch (oc->oncommit)
17946  {
17947  case ONCOMMIT_NOOP:
17949  /* Do nothing (there shouldn't be such entries, actually) */
17950  break;
17951  case ONCOMMIT_DELETE_ROWS:
17952 
17953  /*
17954  * If this transaction hasn't accessed any temporary
17955  * relations, we can skip truncating ON COMMIT DELETE ROWS
17956  * tables, as they must still be empty.
17957  */
17959  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
17960  break;
17961  case ONCOMMIT_DROP:
17962  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
17963  break;
17964  }
17965  }
17966 
17967  /*
17968  * Truncate relations before dropping so that all dependencies between
17969  * relations are removed after they are worked on. Doing it like this
17970  * might be a waste as it is possible that a relation being truncated will
17971  * be dropped anyway due to its parent being dropped, but this makes the
17972  * code more robust because of not having to re-check that the relation
17973  * exists at truncation time.
17974  */
17975  if (oids_to_truncate != NIL)
17976  heap_truncate(oids_to_truncate);
17977 
17978  if (oids_to_drop != NIL)
17979  {
17980  ObjectAddresses *targetObjects = new_object_addresses();
17981 
17982  foreach(l, oids_to_drop)
17983  {
17984  ObjectAddress object;
17985 
17986  object.classId = RelationRelationId;
17987  object.objectId = lfirst_oid(l);
17988  object.objectSubId = 0;
17989 
17990  Assert(!object_address_present(&object, targetObjects));
17991 
17992  add_exact_object_address(&object, targetObjects);
17993  }
17994 
17995  /*
17996  * Object deletion might involve toast table access (to clean up
17997  * toasted catalog entries), so ensure we have a valid snapshot.
17998  */
18000 
18001  /*
18002  * Since this is an automatic drop, rather than one directly initiated
18003  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
18004  */
18005  performMultipleDeletions(targetObjects, DROP_CASCADE,
18007 
18009 
18010 #ifdef USE_ASSERT_CHECKING
18011 
18012  /*
18013  * Note that table deletion will call remove_on_commit_action, so the
18014  * entry should get marked as deleted.
18015  */
18016  foreach(l, on_commits)
18017  {
18018  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
18019 
18020  if (oc->oncommit != ONCOMMIT_DROP)
18021  continue;
18022 
18024  }
18025 #endif
18026  }
18027 }
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:388
#define PERFORM_DELETION_QUIETLY
Definition: dependency.h:138
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:136
void heap_truncate(List *relids)
Definition: heap.c:3339
@ ONCOMMIT_DELETE_ROWS
Definition: primnodes.h:59
@ ONCOMMIT_PRESERVE_ROWS
Definition: primnodes.h:58
@ ONCOMMIT_DROP
Definition: primnodes.h:60
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:223
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:655
void PopActiveSnapshot(void)
Definition: snapmgr.c:750
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, GetTransactionSnapshot(), 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(), PopActiveSnapshot(), PushActiveSnapshot(), 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 18161 of file tablecmds.c.

18163 {
18164  HeapTuple tuple;
18165 
18166  /* Nothing to do if the relation was not found. */
18167  if (!OidIsValid(relId))
18168  return;
18169 
18170  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
18171  if (!HeapTupleIsValid(tuple)) /* should not happen */
18172  elog(ERROR, "cache lookup failed for relation %u", relId);
18173 
18174  if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
18176  relation->relname);
18177 
18178  if (!allowSystemTableMods &&
18179  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
18180  ereport(ERROR,
18181  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
18182  errmsg("permission denied: \"%s\" is a system catalog",
18183  relation->relname)));
18184 
18185  ReleaseSysCache(tuple);
18186 }
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:87
char * relname
Definition: primnodes.h:82

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

Referenced by AlterSequence(), and ProcessUtilitySlow().

◆ RangeVarCallbackOwnsTable()

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

Definition at line 18105 of file tablecmds.c.

18107 {
18108  char relkind;
18109 
18110  /* Nothing to do if the relation was not found. */
18111  if (!OidIsValid(relId))
18112  return;
18113 
18114  /*
18115  * If the relation does exist, check whether it's an index. But note that
18116  * the relation might have been dropped between the time we did the name
18117  * lookup and now. In that case, there's nothing to do.
18118  */
18119  relkind = get_rel_relkind(relId);
18120  if (!relkind)
18121  return;
18122  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
18123  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
18124  ereport(ERROR,
18125  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18126  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
18127 
18128  /* Check permissions */
18129  if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
18131 }

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

17873 {
17874  OnCommitItem *oc;
17875  MemoryContext oldcxt;
17876 
17877  /*
17878  * We needn't bother registering the relation unless there is an ON COMMIT
17879  * action we need to take.
17880  */
17882  return;
17883 
17885 
17886  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
17887  oc->relid = relid;
17888  oc->oncommit = action;
17891 
17892  /*
17893  * We use lcons() here so that ON COMMIT actions are processed in reverse
17894  * order of registration. That might not be essential but it seems
17895  * reasonable.
17896  */
17897  on_commits = lcons(oc, on_commits);
17898 
17899  MemoryContextSwitchTo(oldcxt);
17900 }
List * lcons(void *datum, List *list)
Definition: list.c:495
MemoryContext CacheMemoryContext
Definition: mcxt.c:144
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124

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

17909 {
17910  ListCell *l;
17911 
17912  foreach(l, on_commits)
17913  {
17914  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
17915 
17916  if (oc->relid == relid)
17917  {
17919  break;
17920  }
17921  }
17922 }

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

1474 {
1475  ObjectAddresses *objects;
1476  char relkind;
1477  ListCell *cell;
1478  int flags = 0;
1479  LOCKMODE lockmode = AccessExclusiveLock;
1480 
1481  /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1482  if (drop->concurrent)
1483  {
1484  /*
1485  * Note that for temporary relations this lock may get upgraded later
1486  * on, but as no other session can access a temporary relation, this
1487  * is actually fine.
1488  */
1489  lockmode = ShareUpdateExclusiveLock;
1490  Assert(drop->removeType == OBJECT_INDEX);
1491  if (list_length(drop->objects) != 1)
1492  ereport(ERROR,
1493  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1494  errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1495  if (drop->behavior == DROP_CASCADE)
1496  ereport(ERROR,
1497  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1498  errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1499  }
1500 
1501  /*
1502  * First we identify all the relations, then we delete them in a single
1503  * performMultipleDeletions() call. This is to avoid unwanted DROP
1504  * RESTRICT errors if one of the relations depends on another.
1505  */
1506 
1507  /* Determine required relkind */
1508  switch (drop->removeType)
1509  {
1510  case OBJECT_TABLE:
1511  relkind = RELKIND_RELATION;
1512  break;
1513 
1514  case OBJECT_INDEX:
1515  relkind = RELKIND_INDEX;
1516  break;
1517 
1518  case OBJECT_SEQUENCE:
1519  relkind = RELKIND_SEQUENCE;
1520  break;
1521 
1522  case OBJECT_VIEW:
1523  relkind = RELKIND_VIEW;
1524  break;
1525 
1526  case OBJECT_MATVIEW:
1527  relkind = RELKIND_MATVIEW;
1528  break;
1529 
1530  case OBJECT_FOREIGN_TABLE:
1531  relkind = RELKIND_FOREIGN_TABLE;
1532  break;
1533 
1534  default:
1535  elog(ERROR, "unrecognized drop object type: %d",
1536  (int) drop->removeType);
1537  relkind = 0; /* keep compiler quiet */
1538  break;
1539  }
1540 
1541  /* Lock and validate each relation; build a list of object addresses */
1542  objects = new_object_addresses();
1543 
1544  foreach(cell, drop->objects)
1545  {
1546  RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1547  Oid relOid;
1548  ObjectAddress obj;
1550 
1551  /*
1552  * These next few steps are a great deal like relation_openrv, but we
1553  * don't bother building a relcache entry since we don't need it.
1554  *
1555  * Check for shared-cache-inval messages before trying to access the
1556  * relation. This is needed to cover the case where the name
1557  * identifies a rel that has been dropped and recreated since the
1558  * start of our transaction: if we don't flush the old syscache entry,
1559  * then we'll latch onto that entry and suffer an error later.
1560  */
1562 
1563  /* Look up the appropriate relation using namespace search. */
1564  state.expected_relkind = relkind;
1565  state.heap_lockmode = drop->concurrent ?
1567  /* We must initialize these fields to show that no locks are held: */
1568  state.heapOid = InvalidOid;
1569  state.partParentOid = InvalidOid;
1570 
1571  relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1573  (void *) &state);
1574 
1575  /* Not there? */
1576  if (!OidIsValid(relOid))
1577  {
1578  DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1579  continue;
1580  }
1581 
1582  /*
1583  * Decide if concurrent mode needs to be used here or not. The
1584  * callback retrieved the rel's persistence for us.
1585  */
1586  if (drop->concurrent &&
1587  state.actual_relpersistence != RELPERSISTENCE_TEMP)
1588  {
1589  Assert(list_length(drop->objects) == 1 &&
1590  drop->removeType == OBJECT_INDEX);
1592  }
1593 
1594  /*
1595  * Concurrent index drop cannot be used with partitioned indexes,
1596  * either.
1597  */
1598  if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1599  state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1600  ereport(ERROR,
1601  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1602  errmsg("cannot drop partitioned index \"%s\" concurrently",
1603  rel->relname)));
1604 
1605  /*
1606  * If we're told to drop a partitioned index, we must acquire lock on
1607  * all the children of its parent partitioned table before proceeding.
1608  * Otherwise we'd try to lock the child index partitions before their
1609  * tables, leading to potential deadlock against other sessions that
1610  * will lock those objects in the other order.
1611  */
1612  if (state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1613  (void) find_all_inheritors(state.heapOid,
1614  state.heap_lockmode,
1615  NULL);
1616 
1617  /* OK, we're ready to delete this one */
1618  obj.classId = RelationRelationId;
1619  obj.objectId = relOid;
1620  obj.objectSubId = 0;
1621 
1622  add_exact_object_address(&obj, objects);
1623  }
1624 
1625  performMultipleDeletions(objects, drop->behavior, flags);
1626 
1627  free_object_addresses(objects);
1628 }
#define PERFORM_DELETION_CONCURRENTLY
Definition: dependency.h:137
void AcceptInvalidationMessages(void)
Definition: inval.c:807
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3539
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2114
@ OBJECT_VIEW
Definition: parsenodes.h:2147
bool missing_ok
Definition: parsenodes.h:3072
List * objects
Definition: parsenodes.h:3069
ObjectType removeType
Definition: parsenodes.h:3070
bool concurrent
Definition: parsenodes.h:3073
DropBehavior behavior
Definition: parsenodes.h:3071
Definition: regguts.h:323
static void DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
Definition: tablecmds.c:1398
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:1637

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

3932 {
3933  Oid relid;
3935  ObjectAddress address;
3936 
3937  /* lock level taken here should match renameatt_internal */
3939  stmt->missing_ok ? RVR_MISSING_OK : 0,
3941  NULL);
3942 
3943  if (!OidIsValid(relid))
3944  {
3945  ereport(NOTICE,
3946  (errmsg("relation \"%s\" does not exist, skipping",
3947  stmt->relation->relname)));
3948  return InvalidObjectAddress;
3949  }
3950 
3951  attnum =
3952  renameatt_internal(relid,
3953  stmt->subname, /* old att name */
3954  stmt->newname, /* new att name */
3955  stmt->relation->inh, /* recursive? */
3956  false, /* recursing? */
3957  0, /* expected inhcount */
3958  stmt->behavior);
3959 
3960  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3961 
3962  return address;
3963 }
#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:3766
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3911

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

4079 {
4080  Oid relid = InvalidOid;
4081  Oid typid = InvalidOid;
4082 
4083  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
4084  {
4085  Relation rel;
4086  HeapTuple tup;
4087 
4088  typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
4089  rel = table_open(TypeRelationId, RowExclusiveLock);
4090  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
4091  if (!HeapTupleIsValid(tup))
4092  elog(ERROR, "cache lookup failed for type %u", typid);
4093  checkDomainOwner(tup);
4094  ReleaseSysCache(tup);
4095  table_close(rel, NoLock);
4096  }
4097  else
4098  {
4099  /* lock level taken here should match rename_constraint_internal */
4101  stmt->missing_ok ? RVR_MISSING_OK : 0,
4103  NULL);
4104  if (!OidIsValid(relid))
4105  {
4106  ereport(NOTICE,
4107  (errmsg("relation \"%s\" does not exist, skipping",
4108  stmt->relation->relname)));
4109  return InvalidObjectAddress;
4110  }
4111  }
4112 
4113  return
4114  rename_constraint_internal(relid, typid,
4115  stmt->subname,
4116  stmt->newname,
4117  (stmt->relation &&
4118  stmt->relation->inh), /* recursive? */
4119  false, /* recursing? */
4120  0 /* expected inhcount */ );
4121 }
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:459
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2109
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:3969
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(), and typenameTypeId().

Referenced by ExecRenameStmt().

◆ RenameRelation()

ObjectAddress RenameRelation ( RenameStmt stmt)

Definition at line 4128 of file tablecmds.c.

4129 {
4130  bool is_index_stmt = stmt->renameType == OBJECT_INDEX;
4131  Oid relid;
4132  ObjectAddress address;
4133 
4134  /*
4135  * Grab an exclusive lock on the target table, index, sequence, view,
4136  * materialized view, or foreign table, which we will NOT release until
4137  * end of transaction.
4138  *
4139  * Lock level used here should match RenameRelationInternal, to avoid lock
4140  * escalation. However, because ALTER INDEX can be used with any relation
4141  * type, we mustn't believe without verification.
4142  */
4143  for (;;)
4144  {
4145  LOCKMODE lockmode;
4146  char relkind;
4147  bool obj_is_index;
4148 
4149  lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
4150 
4151  relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
4152  stmt->missing_ok ? RVR_MISSING_OK : 0,
4154  (void *) stmt);
4155 
4156  if (!OidIsValid(relid))
4157  {
4158  ereport(NOTICE,
4159  (errmsg("relation \"%s\" does not exist, skipping",
4160  stmt->relation->relname)));
4161  return InvalidObjectAddress;
4162  }
4163 
4164  /*
4165  * We allow mismatched statement and object types (e.g., ALTER INDEX
4166  * to rename a table), but we might've used the wrong lock level. If
4167  * that happens, retry with the correct lock level. We don't bother
4168  * if we already acquired AccessExclusiveLock with an index, however.
4169  */
4170  relkind = get_rel_relkind(relid);
4171  obj_is_index = (relkind == RELKIND_INDEX ||
4172  relkind == RELKIND_PARTITIONED_INDEX);
4173  if (obj_is_index || is_index_stmt == obj_is_index)
4174  break;
4175 
4176  UnlockRelationOid(relid, lockmode);
4177  is_index_stmt = obj_is_index;
4178  }
4179 
4180  /* Do the work */
4181  RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
4182 
4183  ObjectAddressSet(address, RelationRelationId, relid);
4184 
4185  return address;
4186 }
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:4192

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

4193 {
4194  Relation targetrelation;
4195  Relation relrelation; /* for RELATION relation */
4196  HeapTuple reltup;
4197  Form_pg_class relform;
4198  Oid namespaceId;
4199 
4200  /*
4201  * Grab a lock on the target relation, which we will NOT release until end
4202  * of transaction. We need at least a self-exclusive lock so that
4203  * concurrent DDL doesn't overwrite the rename if they start updating
4204  * while still seeing the old version. The lock also guards against
4205  * triggering relcache reloads in concurrent sessions, which might not
4206  * handle this information changing under them. For indexes, we can use a
4207  * reduced lock level because RelationReloadIndexInfo() handles indexes
4208  * specially.
4209  */
4210  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
4211  namespaceId = RelationGetNamespace(targetrelation);
4212 
4213  /*
4214  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
4215  */
4216  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4217 
4218  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4219  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4220  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4221  relform = (Form_pg_class) GETSTRUCT(reltup);
4222 
4223  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
4224  ereport(ERROR,
4225  (errcode(ERRCODE_DUPLICATE_TABLE),
4226  errmsg("relation \"%s\" already exists",
4227  newrelname)));
4228 
4229  /*
4230  * RenameRelation is careful not to believe the caller's idea of the
4231  * relation kind being handled. We don't have to worry about this, but
4232  * let's not be totally oblivious to it. We can process an index as
4233  * not-an-index, but not the other way around.
4234  */
4235  Assert(!is_index ||
4236  is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4237  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
4238 
4239  /*
4240  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
4241  * because it's a copy...)
4242  */
4243  namestrcpy(&(relform->relname), newrelname);
4244 
4245  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4246 
4247  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
4248  InvalidOid, is_internal);
4249 
4250  heap_freetuple(reltup);
4251  table_close(relrelation, RowExclusiveLock);
4252 
4253  /*
4254  * Also rename the associated type, if any.
4255  */
4256  if (OidIsValid(targetrelation->rd_rel->reltype))
4257  RenameTypeInternal(targetrelation->rd_rel->reltype,
4258  newrelname, namespaceId);
4259 
4260  /*
4261  * Also rename the associated constraint, if any.
4262  */
4263  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4264  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4265  {
4266  Oid constraintId = get_index_constraint(myrelid);
4267 
4268  if (OidIsValid(constraintId))
4269  RenameConstraintById(constraintId, newrelname);
4270  }
4271 
4272  /*
4273  * Close rel, but keep lock!
4274  */
4275  relation_close(targetrelation, NoLock);
4276 }
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:759

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

4283 {
4284  Relation relrelation; /* for RELATION relation */
4285  HeapTuple reltup;
4286  Form_pg_class relform;
4287 
4288  /*
4289  * Find relation's pg_class tuple.
4290  */
4291  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4292 
4293  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4294  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4295  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4296  relform = (Form_pg_class) GETSTRUCT(reltup);
4297 
4298  /*
4299  * Update pg_class tuple.
4300  */
4301  relform->relrewrite = InvalidOid;
4302 
4303  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4304 
4305  heap_freetuple(reltup);
4306  table_close(relrelation, RowExclusiveLock);
4307 }

References CatalogTupleUpdate(), elog(), ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), 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 3577 of file tablecmds.c.

3578 {
3579  Relation relationRelation;
3580  HeapTuple tuple;
3581  Form_pg_class classtuple;
3582 
3583  /*
3584  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3585  */
3586  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3587  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3588  if (!HeapTupleIsValid(tuple))
3589  elog(ERROR, "cache lookup failed for relation %u", relationId);
3590  classtuple = (Form_pg_class) GETSTRUCT(tuple);
3591 
3592  if (classtuple->relhassubclass != relhassubclass)
3593  {
3594  classtuple->relhassubclass = relhassubclass;
3595  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3596  }
3597  else
3598  {
3599  /* no need to change tuple, but force relcache rebuild anyway */
3601  }
3602 
3603  heap_freetuple(tuple);
3604  table_close(relationRelation, RowExclusiveLock);
3605 }
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1397

References CacheInvalidateRelcacheByTuple(), CatalogTupleUpdate(), elog(), ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, ObjectIdGetDatum(), 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 3675 of file tablecmds.c.

3678 {
3679  Relation pg_class;
3680  HeapTuple tuple;
3681  Form_pg_class rd_rel;
3682  Oid reloid = RelationGetRelid(rel);
3683 
3684  Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3685 
3686  /* Get a modifiable copy of the relation's pg_class row. */
3687  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3688 
3689  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
3690  if (!HeapTupleIsValid(tuple))
3691  elog(ERROR, "cache lookup failed for relation %u", reloid);
3692  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3693 
3694  /* Update the pg_class row. */
3695  rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3696  InvalidOid : newTableSpaceId;
3697  if (RelFileNumberIsValid(newRelFilenumber))
3698  rd_rel->relfilenode = newRelFilenumber;
3699  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3700 
3701  /*
3702  * Record dependency on tablespace. This is only required for relations
3703  * that have no physical storage.
3704  */
3705  if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3706  changeDependencyOnTablespace(RelationRelationId, reloid,
3707  rd_rel->reltablespace);
3708 
3709  heap_freetuple(tuple);
3710  table_close(pg_class, RowExclusiveLock);
3711 }
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:3618

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

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