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

Go to the source code of this file.

Functions

ObjectAddress DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
 
void RemoveRelations (DropStmt *drop)
 
Oid AlterTableLookupRelation (AlterTableStmt *stmt, LOCKMODE lockmode)
 
void AlterTable (AlterTableStmt *stmt, LOCKMODE lockmode, struct AlterTableUtilityContext *context)
 
LOCKMODE AlterTableGetLockLevel (List *cmds)
 
void ATExecChangeOwner (Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
 
void AlterTableInternal (Oid relid, List *cmds, bool recurse)
 
Oid AlterTableMoveAll (AlterTableMoveAllStmt *stmt)
 
ObjectAddress AlterTableNamespace (AlterObjectSchemaStmt *stmt, Oid *oldschema)
 
void AlterTableNamespaceInternal (Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
 
void AlterRelationNamespaceInternal (Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
 
void CheckTableNotInUse (Relation rel, const char *stmt)
 
void ExecuteTruncate (TruncateStmt *stmt)
 
void ExecuteTruncateGuts (List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs)
 
void SetRelationHasSubclass (Oid relationId, bool relhassubclass)
 
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 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 15178 of file tablecmds.c.

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

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

15182 {
15183  HeapTuple classTup;
15184  Form_pg_class classForm;
15185  ObjectAddress thisobj;
15186  bool already_done = false;
15187 
15188  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
15189  if (!HeapTupleIsValid(classTup))
15190  elog(ERROR, "cache lookup failed for relation %u", relOid);
15191  classForm = (Form_pg_class) GETSTRUCT(classTup);
15192 
15193  Assert(classForm->relnamespace == oldNspOid);
15194 
15195  thisobj.classId = RelationRelationId;
15196  thisobj.objectId = relOid;
15197  thisobj.objectSubId = 0;
15198 
15199  /*
15200  * If the object has already been moved, don't move it again. If it's
15201  * already in the right place, don't move it, but still fire the object
15202  * access hook.
15203  */
15204  already_done = object_address_present(&thisobj, objsMoved);
15205  if (!already_done && oldNspOid != newNspOid)
15206  {
15207  /* check for duplicate name (more friendly than unique-index failure) */
15208  if (get_relname_relid(NameStr(classForm->relname),
15209  newNspOid) != InvalidOid)
15210  ereport(ERROR,
15211  (errcode(ERRCODE_DUPLICATE_TABLE),
15212  errmsg("relation \"%s\" already exists in schema \"%s\"",
15213  NameStr(classForm->relname),
15214  get_namespace_name(newNspOid))));
15215 
15216  /* classTup is a copy, so OK to scribble on */
15217  classForm->relnamespace = newNspOid;
15218 
15219  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
15220 
15221  /* Update dependency on schema if caller said so */
15222  if (hasDependEntry &&
15223  changeDependencyFor(RelationRelationId,
15224  relOid,
15225  NamespaceRelationId,
15226  oldNspOid,
15227  newNspOid) != 1)
15228  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
15229  NameStr(classForm->relname));
15230  }
15231  if (!already_done)
15232  {
15233  add_exact_object_address(&thisobj, objsMoved);
15234 
15235  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
15236  }
15237 
15238  heap_freetuple(classTup);
15239 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2670
int errcode(int sqlerrcode)
Definition: elog.c:704
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2610
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:45
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1829
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3289
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:155
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:792
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:302
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
int errmsg(const char *fmt,...)
Definition: elog.c:915
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:428
#define elog(elevel,...)
Definition: elog.h:228
#define NameStr(name)
Definition: c.h:669

◆ AlterTable()

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

Definition at line 3678 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3680 {
3681  Relation rel;
3682 
3683  /* Caller is required to provide an adequate lock. */
3684  rel = relation_open(context->relid, NoLock);
3685 
3686  CheckTableNotInUse(rel, "ALTER TABLE");
3687 
3688  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
3689 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4018
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3594
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1801

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 3752 of file tablecmds.c.

References AccessExclusiveLock, AccessShareLock, AlterTableGetRelOptionsLockLevel(), AT_AddColumn, AT_AddColumnToView, AT_AddConstraint, AT_AddConstraintRecurse, AT_AddIdentity, AT_AddIndex, AT_AddIndexConstraint, AT_AddInherit, AT_AddOf, AT_AlterCollationRefreshVersion, AT_AlterColumnGenericOptions, AT_AlterColumnType, AT_AlterConstraint, AT_AttachPartition, AT_ChangeOwner, AT_CheckNotNull, AT_ClusterOn, AT_ColumnDefault, AT_CookedColumnDefault, AT_DetachPartition, 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_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().

3753 {
3754  /*
3755  * This only works if we read catalog tables using MVCC snapshots.
3756  */
3757  ListCell *lcmd;
3759 
3760  foreach(lcmd, cmds)
3761  {
3762  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3763  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
3764 
3765  switch (cmd->subtype)
3766  {
3767  /*
3768  * These subcommands rewrite the heap, so require full locks.
3769  */
3770  case AT_AddColumn: /* may rewrite heap, in some cases and visible
3771  * to SELECT */
3772  case AT_SetTableSpace: /* must rewrite heap */
3773  case AT_AlterColumnType: /* must rewrite heap */
3774  cmd_lockmode = AccessExclusiveLock;
3775  break;
3776 
3777  /*
3778  * These subcommands may require addition of toast tables. If
3779  * we add a toast table to a table currently being scanned, we
3780  * might miss data added to the new toast table by concurrent
3781  * insert transactions.
3782  */
3783  case AT_SetStorage: /* may add toast tables, see
3784  * ATRewriteCatalogs() */
3785  cmd_lockmode = AccessExclusiveLock;
3786  break;
3787 
3788  /*
3789  * Removing constraints can affect SELECTs that have been
3790  * optimized assuming the constraint holds true. See also
3791  * CloneFkReferenced.
3792  */
3793  case AT_DropConstraint: /* as DROP INDEX */
3794  case AT_DropNotNull: /* may change some SQL plans */
3795  cmd_lockmode = AccessExclusiveLock;
3796  break;
3797 
3798  /*
3799  * Subcommands that may be visible to concurrent SELECTs
3800  */
3801  case AT_DropColumn: /* change visible to SELECT */
3802  case AT_AddColumnToView: /* CREATE VIEW */
3803  case AT_DropOids: /* used to equiv to DropColumn */
3804  case AT_EnableAlwaysRule: /* may change SELECT rules */
3805  case AT_EnableReplicaRule: /* may change SELECT rules */
3806  case AT_EnableRule: /* may change SELECT rules */
3807  case AT_DisableRule: /* may change SELECT rules */
3808  cmd_lockmode = AccessExclusiveLock;
3809  break;
3810 
3811  /*
3812  * Changing owner may remove implicit SELECT privileges
3813  */
3814  case AT_ChangeOwner: /* change visible to SELECT */
3815  cmd_lockmode = AccessExclusiveLock;
3816  break;
3817 
3818  /*
3819  * Changing foreign table options may affect optimization.
3820  */
3821  case AT_GenericOptions:
3823  cmd_lockmode = AccessExclusiveLock;
3824  break;
3825 
3826  /*
3827  * These subcommands affect write operations only.
3828  */
3829  case AT_EnableTrig:
3830  case AT_EnableAlwaysTrig:
3831  case AT_EnableReplicaTrig:
3832  case AT_EnableTrigAll:
3833  case AT_EnableTrigUser:
3834  case AT_DisableTrig:
3835  case AT_DisableTrigAll:
3836  case AT_DisableTrigUser:
3837  cmd_lockmode = ShareRowExclusiveLock;
3838  break;
3839 
3840  /*
3841  * These subcommands affect write operations only. XXX
3842  * Theoretically, these could be ShareRowExclusiveLock.
3843  */
3844  case AT_ColumnDefault:
3846  case AT_AlterConstraint:
3847  case AT_AddIndex: /* from ADD CONSTRAINT */
3848  case AT_AddIndexConstraint:
3849  case AT_ReplicaIdentity:
3850  case AT_SetNotNull:
3851  case AT_EnableRowSecurity:
3852  case AT_DisableRowSecurity:
3853  case AT_ForceRowSecurity:
3854  case AT_NoForceRowSecurity:
3855  case AT_AddIdentity:
3856  case AT_DropIdentity:
3857  case AT_SetIdentity:
3858  case AT_DropExpression:
3859  cmd_lockmode = AccessExclusiveLock;
3860  break;
3861 
3862  case AT_AddConstraint:
3863  case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
3864  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
3865  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
3866  if (IsA(cmd->def, Constraint))
3867  {
3868  Constraint *con = (Constraint *) cmd->def;
3869 
3870  switch (con->contype)
3871  {
3872  case CONSTR_EXCLUSION:
3873  case CONSTR_PRIMARY:
3874  case CONSTR_UNIQUE:
3875 
3876  /*
3877  * Cases essentially the same as CREATE INDEX. We
3878  * could reduce the lock strength to ShareLock if
3879  * we can work out how to allow concurrent catalog
3880  * updates. XXX Might be set down to
3881  * ShareRowExclusiveLock but requires further
3882  * analysis.
3883  */
3884  cmd_lockmode = AccessExclusiveLock;
3885  break;
3886  case CONSTR_FOREIGN:
3887 
3888  /*
3889  * We add triggers to both tables when we add a
3890  * Foreign Key, so the lock level must be at least
3891  * as strong as CREATE TRIGGER.
3892  */
3893  cmd_lockmode = ShareRowExclusiveLock;
3894  break;
3895 
3896  default:
3897  cmd_lockmode = AccessExclusiveLock;
3898  }
3899  }
3900  break;
3901 
3902  /*
3903  * These subcommands affect inheritance behaviour. Queries
3904  * started before us will continue to see the old inheritance
3905  * behaviour, while queries started after we commit will see
3906  * new behaviour. No need to prevent reads or writes to the
3907  * subtable while we hook it up though. Changing the TupDesc
3908  * may be a problem, so keep highest lock.
3909  */
3910  case AT_AddInherit:
3911  case AT_DropInherit:
3912  cmd_lockmode = AccessExclusiveLock;
3913  break;
3914 
3915  /*
3916  * These subcommands affect implicit row type conversion. They
3917  * have affects similar to CREATE/DROP CAST on queries. don't
3918  * provide for invalidating parse trees as a result of such
3919  * changes, so we keep these at AccessExclusiveLock.
3920  */
3921  case AT_AddOf:
3922  case AT_DropOf:
3923  cmd_lockmode = AccessExclusiveLock;
3924  break;
3925 
3926  /*
3927  * Only used by CREATE OR REPLACE VIEW which must conflict
3928  * with an SELECTs currently using the view.
3929  */
3930  case AT_ReplaceRelOptions:
3931  cmd_lockmode = AccessExclusiveLock;
3932  break;
3933 
3934  /*
3935  * These subcommands affect general strategies for performance
3936  * and maintenance, though don't change the semantic results
3937  * from normal data reads and writes. Delaying an ALTER TABLE
3938  * behind currently active writes only delays the point where
3939  * the new strategy begins to take effect, so there is no
3940  * benefit in waiting. In this case the minimum restriction
3941  * applies: we don't currently allow concurrent catalog
3942  * updates.
3943  */
3944  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
3945  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
3946  case AT_DropCluster: /* Uses MVCC in getIndexes() */
3947  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
3948  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
3949  cmd_lockmode = ShareUpdateExclusiveLock;
3950  break;
3951 
3952  case AT_SetLogged:
3953  case AT_SetUnLogged:
3954  cmd_lockmode = AccessExclusiveLock;
3955  break;
3956 
3957  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
3958  cmd_lockmode = ShareUpdateExclusiveLock;
3959  break;
3960 
3961  /*
3962  * Rel options are more complex than first appears. Options
3963  * are set here for tables, views and indexes; for historical
3964  * reasons these can all be used with ALTER TABLE, so we can't
3965  * decide between them using the basic grammar.
3966  */
3967  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
3968  * getTables() */
3969  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
3970  * getTables() */
3971  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
3972  break;
3973 
3974  case AT_AttachPartition:
3975  cmd_lockmode = ShareUpdateExclusiveLock;
3976  break;
3977 
3978  case AT_DetachPartition:
3979  cmd_lockmode = AccessExclusiveLock;
3980  break;
3981 
3982  case AT_CheckNotNull:
3983 
3984  /*
3985  * This only examines the table's schema; but lock must be
3986  * strong enough to prevent concurrent DROP NOT NULL.
3987  */
3988  cmd_lockmode = AccessShareLock;
3989  break;
3990 
3992  cmd_lockmode = AccessExclusiveLock;
3993  break;
3994 
3995  default: /* oops */
3996  elog(ERROR, "unrecognized alter table type: %d",
3997  (int) cmd->subtype);
3998  break;
3999  }
4000 
4001  /*
4002  * Take the greatest lockmode from any subcommand
4003  */
4004  if (cmd_lockmode > lockmode)
4005  lockmode = cmd_lockmode;
4006  }
4007 
4008  return lockmode;
4009 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
int LOCKMODE
Definition: lockdefs.h:26
#define AccessShareLock
Definition: lockdefs.h:36
AlterTableType subtype
Definition: parsenodes.h:1889
#define ERROR
Definition: elog.h:45
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define lfirst(lc)
Definition: pg_list.h:169
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2085
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define elog(elevel,...)
Definition: elog.h:228
ConstrType contype
Definition: parsenodes.h:2168
Definition: pg_list.h:50

◆ AlterTableInternal()

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

Definition at line 3707 of file tablecmds.c.

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

3708 {
3709  Relation rel;
3710  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
3711 
3712  rel = relation_open(relid, lockmode);
3713 
3715 
3716  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
3717 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4018
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:3752
void EventTriggerAlterTableRelid(Oid objectId)

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3622 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3623 {
3624  return RangeVarGetRelidExtended(stmt->relation, lockmode,
3625  stmt->missing_ok ? RVR_MISSING_OK : 0,
3627  (void *) stmt);
3628 }
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:15692
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
RangeVar * relation
Definition: parsenodes.h:1801

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 13372 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

13373 {
13374  List *relations = NIL;
13375  ListCell *l;
13376  ScanKeyData key[1];
13377  Relation rel;
13378  TableScanDesc scan;
13379  HeapTuple tuple;
13380  Oid orig_tablespaceoid;
13381  Oid new_tablespaceoid;
13382  List *role_oids = roleSpecsToIds(stmt->roles);
13383 
13384  /* Ensure we were not asked to move something we can't */
13385  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
13386  stmt->objtype != OBJECT_MATVIEW)
13387  ereport(ERROR,
13388  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13389  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
13390 
13391  /* Get the orig and new tablespace OIDs */
13392  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
13393  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
13394 
13395  /* Can't move shared relations in to or out of pg_global */
13396  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
13397  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
13398  new_tablespaceoid == GLOBALTABLESPACE_OID)
13399  ereport(ERROR,
13400  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13401  errmsg("cannot move relations in to or out of pg_global tablespace")));
13402 
13403  /*
13404  * Must have CREATE rights on the new tablespace, unless it is the
13405  * database default tablespace (which all users implicitly have CREATE
13406  * rights on).
13407  */
13408  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
13409  {
13410  AclResult aclresult;
13411 
13412  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
13413  ACL_CREATE);
13414  if (aclresult != ACLCHECK_OK)
13415  aclcheck_error(aclresult, OBJECT_TABLESPACE,
13416  get_tablespace_name(new_tablespaceoid));
13417  }
13418 
13419  /*
13420  * Now that the checks are done, check if we should set either to
13421  * InvalidOid because it is our database's default tablespace.
13422  */
13423  if (orig_tablespaceoid == MyDatabaseTableSpace)
13424  orig_tablespaceoid = InvalidOid;
13425 
13426  if (new_tablespaceoid == MyDatabaseTableSpace)
13427  new_tablespaceoid = InvalidOid;
13428 
13429  /* no-op */
13430  if (orig_tablespaceoid == new_tablespaceoid)
13431  return new_tablespaceoid;
13432 
13433  /*
13434  * Walk the list of objects in the tablespace and move them. This will
13435  * only find objects in our database, of course.
13436  */
13437  ScanKeyInit(&key[0],
13438  Anum_pg_class_reltablespace,
13439  BTEqualStrategyNumber, F_OIDEQ,
13440  ObjectIdGetDatum(orig_tablespaceoid));
13441 
13442  rel = table_open(RelationRelationId, AccessShareLock);
13443  scan = table_beginscan_catalog(rel, 1, key);
13444  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
13445  {
13446  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
13447  Oid relOid = relForm->oid;
13448 
13449  /*
13450  * Do not move objects in pg_catalog as part of this, if an admin
13451  * really wishes to do so, they can issue the individual ALTER
13452  * commands directly.
13453  *
13454  * Also, explicitly avoid any shared tables, temp tables, or TOAST
13455  * (TOAST will be moved with the main table).
13456  */
13457  if (IsCatalogNamespace(relForm->relnamespace) ||
13458  relForm->relisshared ||
13459  isAnyTempNamespace(relForm->relnamespace) ||
13460  IsToastNamespace(relForm->relnamespace))
13461  continue;
13462 
13463  /* Only move the object type requested */
13464  if ((stmt->objtype == OBJECT_TABLE &&
13465  relForm->relkind != RELKIND_RELATION &&
13466  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
13467  (stmt->objtype == OBJECT_INDEX &&
13468  relForm->relkind != RELKIND_INDEX &&
13469  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
13470  (stmt->objtype == OBJECT_MATVIEW &&
13471  relForm->relkind != RELKIND_MATVIEW))
13472  continue;
13473 
13474  /* Check if we are only moving objects owned by certain roles */
13475  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
13476  continue;
13477 
13478  /*
13479  * Handle permissions-checking here since we are locking the tables
13480  * and also to avoid doing a bunch of work only to fail part-way. Note
13481  * that permissions will also be checked by AlterTableInternal().
13482  *
13483  * Caller must be considered an owner on the table to move it.
13484  */
13485  if (!pg_class_ownercheck(relOid, GetUserId()))
13487  NameStr(relForm->relname));
13488 
13489  if (stmt->nowait &&
13491  ereport(ERROR,
13492  (errcode(ERRCODE_OBJECT_IN_USE),
13493  errmsg("aborting because lock on relation \"%s.%s\" is not available",
13494  get_namespace_name(relForm->relnamespace),
13495  NameStr(relForm->relname))));
13496  else
13498 
13499  /* Add to our list of objects to move */
13500  relations = lappend_oid(relations, relOid);
13501  }
13502 
13503  table_endscan(scan);
13505 
13506  if (relations == NIL)
13507  ereport(NOTICE,
13508  (errcode(ERRCODE_NO_DATA_FOUND),
13509  errmsg("no matching relations in tablespace \"%s\" found",
13510  orig_tablespaceoid == InvalidOid ? "(database default)" :
13511  get_tablespace_name(orig_tablespaceoid))));
13512 
13513  /* Everything is locked, loop through and move all of the relations. */
13514  foreach(l, relations)
13515  {
13516  List *cmds = NIL;
13518 
13519  cmd->subtype = AT_SetTableSpace;
13520  cmd->name = stmt->new_tablespacename;
13521 
13522  cmds = lappend(cmds, cmd);
13523 
13525  /* OID is set by AlterTableInternal */
13526  AlterTableInternal(lfirst_oid(l), cmds, false);
13528  }
13529 
13530  return new_tablespaceoid;
13531 }
#define NIL
Definition: pg_list.h:65
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:151
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1433
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4637
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
Oid GetUserId(void)
Definition: miscinit.c:476
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1947
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:528
int errcode(int sqlerrcode)
Definition: elog.c:704
AlterTableType subtype
Definition: parsenodes.h:1889
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:193
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
#define OidIsValid(objectId)
Definition: c.h:698
Oid MyDatabaseTableSpace
Definition: globals.c:88
void EventTriggerAlterTableStart(Node *parsetree)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:45
#define ACL_CREATE
Definition: parsenodes.h:84
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3289
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1304
List * lappend(List *list, void *datum)
Definition: list.c:321
AclResult
Definition: acl.h:177
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:155
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:576
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1436
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:674
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4687
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:175
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:962
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:3707
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:915
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1479
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:669
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3194
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:171
void EventTriggerAlterTableEnd(void)

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 15068 of file tablecmds.c.

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

Referenced by ExecAlterObjectSchemaStmt().

15069 {
15070  Relation rel;
15071  Oid relid;
15072  Oid oldNspOid;
15073  Oid nspOid;
15074  RangeVar *newrv;
15075  ObjectAddresses *objsMoved;
15076  ObjectAddress myself;
15077 
15079  stmt->missing_ok ? RVR_MISSING_OK : 0,
15081  (void *) stmt);
15082 
15083  if (!OidIsValid(relid))
15084  {
15085  ereport(NOTICE,
15086  (errmsg("relation \"%s\" does not exist, skipping",
15087  stmt->relation->relname)));
15088  return InvalidObjectAddress;
15089  }
15090 
15091  rel = relation_open(relid, NoLock);
15092 
15093  oldNspOid = RelationGetNamespace(rel);
15094 
15095  /* If it's an owned sequence, disallow moving it by itself. */
15096  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
15097  {
15098  Oid tableId;
15099  int32 colId;
15100 
15101  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
15102  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
15103  ereport(ERROR,
15104  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15105  errmsg("cannot move an owned sequence into another schema"),
15106  errdetail("Sequence \"%s\" is linked to table \"%s\".",
15108  get_rel_name(tableId))));
15109  }
15110 
15111  /* Get and lock schema OID and check its permissions. */
15112  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
15113  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
15114 
15115  /* common checks on switching namespaces */
15116  CheckSetNamespace(oldNspOid, nspOid);
15117 
15118  objsMoved = new_object_addresses();
15119  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
15120  free_object_addresses(objsMoved);
15121 
15122  ObjectAddressSet(myself, RelationRelationId, relid);
15123 
15124  if (oldschema)
15125  *oldschema = oldNspOid;
15126 
15127  /* close rel, but keep lock until commit */
15128  relation_close(rel, NoLock);
15129 
15130  return myself;
15131 }
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:837
int errcode(int sqlerrcode)
Definition: elog.c:704
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2555
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2851
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:698
signed int int32
Definition: c.h:417
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:45
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15139
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:15692
int errdetail(const char *fmt,...)
Definition: elog.c:1048
#define RelationGetRelationName(relation)
Definition: rel.h:491
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2966
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:534
#define ereport(elevel,...)
Definition: elog.h:155
#define NOTICE
Definition: elog.h:37
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:915
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1872
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:422
#define RelationGetNamespace(relation)
Definition: rel.h:498

◆ AlterTableNamespaceInternal()

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

Definition at line 15139 of file tablecmds.c.

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

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

15141 {
15142  Relation classRel;
15143 
15144  Assert(objsMoved != NULL);
15145 
15146  /* OK, modify the pg_class row and pg_depend entry */
15147  classRel = table_open(RelationRelationId, RowExclusiveLock);
15148 
15149  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
15150  nspOid, true, objsMoved);
15151 
15152  /* Fix the table's row type too, if it has one */
15153  if (OidIsValid(rel->rd_rel->reltype))
15154  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
15155  nspOid, false, false, objsMoved);
15156 
15157  /* Fix other dependent stuff */
15158  if (rel->rd_rel->relkind == RELKIND_RELATION ||
15159  rel->rd_rel->relkind == RELKIND_MATVIEW ||
15160  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15161  {
15162  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
15163  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
15164  objsMoved, AccessExclusiveLock);
15165  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
15166  false, objsMoved);
15167  }
15168 
15169  table_close(classRel, RowExclusiveLock);
15170 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3966
Form_pg_class rd_rel
Definition: rel.h:110
#define OidIsValid(objectId)
Definition: c.h:698
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15248
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:15293
#define RowExclusiveLock
Definition: lockdefs.h:38
#define Assert(condition)
Definition: c.h:792
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15178
#define AccessExclusiveLock
Definition: lockdefs.h:45
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:457

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 15569 of file tablecmds.c.

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

15571 {
15572  ListCell *cur_item;
15573 
15574  foreach(cur_item, on_commits)
15575  {
15576  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
15577 
15578  if (!isCommit && oc->creating_subid == mySubid)
15579  {
15580  /* cur_item must be removed */
15582  pfree(oc);
15583  }
15584  else
15585  {
15586  /* cur_item must be preserved */
15587  if (oc->creating_subid == mySubid)
15588  oc->creating_subid = parentSubid;
15589  if (oc->deleting_subid == mySubid)
15590  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
15591  }
15592  }
15593 }
SubTransactionId creating_subid
Definition: tablecmds.c:117
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:357
void pfree(void *pointer)
Definition: mcxt.c:1057
static List * on_commits
Definition: tablecmds.c:121
SubTransactionId deleting_subid
Definition: tablecmds.c:118
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:581

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 15537 of file tablecmds.c.

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

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

15538 {
15539  ListCell *cur_item;
15540 
15541  foreach(cur_item, on_commits)
15542  {
15543  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
15544 
15545  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
15547  {
15548  /* cur_item must be removed */
15550  pfree(oc);
15551  }
15552  else
15553  {
15554  /* cur_item must be preserved */
15557  }
15558  }
15559 }
SubTransactionId creating_subid
Definition: tablecmds.c:117
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:357
void pfree(void *pointer)
Definition: mcxt.c:1057
static List * on_commits
Definition: tablecmds.c:121
SubTransactionId deleting_subid
Definition: tablecmds.c:118
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:581

◆ ATExecChangeOwner()

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

Definition at line 12515 of file tablecmds.c.

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

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

12516 {
12517  Relation target_rel;
12518  Relation class_rel;
12519  HeapTuple tuple;
12520  Form_pg_class tuple_class;
12521 
12522  /*
12523  * Get exclusive lock till end of transaction on the target table. Use
12524  * relation_open so that we can work on indexes and sequences.
12525  */
12526  target_rel = relation_open(relationOid, lockmode);
12527 
12528  /* Get its pg_class tuple, too */
12529  class_rel = table_open(RelationRelationId, RowExclusiveLock);
12530 
12531  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
12532  if (!HeapTupleIsValid(tuple))
12533  elog(ERROR, "cache lookup failed for relation %u", relationOid);
12534  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
12535 
12536  /* Can we change the ownership of this tuple? */
12537  switch (tuple_class->relkind)
12538  {
12539  case RELKIND_RELATION:
12540  case RELKIND_VIEW:
12541  case RELKIND_MATVIEW:
12542  case RELKIND_FOREIGN_TABLE:
12543  case RELKIND_PARTITIONED_TABLE:
12544  /* ok to change owner */
12545  break;
12546  case RELKIND_INDEX:
12547  if (!recursing)
12548  {
12549  /*
12550  * Because ALTER INDEX OWNER used to be allowed, and in fact
12551  * is generated by old versions of pg_dump, we give a warning
12552  * and do nothing rather than erroring out. Also, to avoid
12553  * unnecessary chatter while restoring those old dumps, say
12554  * nothing at all if the command would be a no-op anyway.
12555  */
12556  if (tuple_class->relowner != newOwnerId)
12557  ereport(WARNING,
12558  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12559  errmsg("cannot change owner of index \"%s\"",
12560  NameStr(tuple_class->relname)),
12561  errhint("Change the ownership of the index's table, instead.")));
12562  /* quick hack to exit via the no-op path */
12563  newOwnerId = tuple_class->relowner;
12564  }
12565  break;
12566  case RELKIND_PARTITIONED_INDEX:
12567  if (recursing)
12568  break;
12569  ereport(ERROR,
12570  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12571  errmsg("cannot change owner of index \"%s\"",
12572  NameStr(tuple_class->relname)),
12573  errhint("Change the ownership of the index's table, instead.")));
12574  break;
12575  case RELKIND_SEQUENCE:
12576  if (!recursing &&
12577  tuple_class->relowner != newOwnerId)
12578  {
12579  /* if it's an owned sequence, disallow changing it by itself */
12580  Oid tableId;
12581  int32 colId;
12582 
12583  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
12584  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
12585  ereport(ERROR,
12586  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12587  errmsg("cannot change owner of sequence \"%s\"",
12588  NameStr(tuple_class->relname)),
12589  errdetail("Sequence \"%s\" is linked to table \"%s\".",
12590  NameStr(tuple_class->relname),
12591  get_rel_name(tableId))));
12592  }
12593  break;
12594  case RELKIND_COMPOSITE_TYPE:
12595  if (recursing)
12596  break;
12597  ereport(ERROR,
12598  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12599  errmsg("\"%s\" is a composite type",
12600  NameStr(tuple_class->relname)),
12601  errhint("Use ALTER TYPE instead.")));
12602  break;
12603  case RELKIND_TOASTVALUE:
12604  if (recursing)
12605  break;
12606  /* FALL THRU */
12607  default:
12608  ereport(ERROR,
12609  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12610  errmsg("\"%s\" is not a table, view, sequence, or foreign table",
12611  NameStr(tuple_class->relname))));
12612  }
12613 
12614  /*
12615  * If the new owner is the same as the existing owner, consider the
12616  * command to have succeeded. This is for dump restoration purposes.
12617  */
12618  if (tuple_class->relowner != newOwnerId)
12619  {
12620  Datum repl_val[Natts_pg_class];
12621  bool repl_null[Natts_pg_class];
12622  bool repl_repl[Natts_pg_class];
12623  Acl *newAcl;
12624  Datum aclDatum;
12625  bool isNull;
12626  HeapTuple newtuple;
12627 
12628  /* skip permission checks when recursing to index or toast table */
12629  if (!recursing)
12630  {
12631  /* Superusers can always do it */
12632  if (!superuser())
12633  {
12634  Oid namespaceOid = tuple_class->relnamespace;
12635  AclResult aclresult;
12636 
12637  /* Otherwise, must be owner of the existing object */
12638  if (!pg_class_ownercheck(relationOid, GetUserId()))
12640  RelationGetRelationName(target_rel));
12641 
12642  /* Must be able to become new owner */
12643  check_is_member_of_role(GetUserId(), newOwnerId);
12644 
12645  /* New owner must have CREATE privilege on namespace */
12646  aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
12647  ACL_CREATE);
12648  if (aclresult != ACLCHECK_OK)
12649  aclcheck_error(aclresult, OBJECT_SCHEMA,
12650  get_namespace_name(namespaceOid));
12651  }
12652  }
12653 
12654  memset(repl_null, false, sizeof(repl_null));
12655  memset(repl_repl, false, sizeof(repl_repl));
12656 
12657  repl_repl[Anum_pg_class_relowner - 1] = true;
12658  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
12659 
12660  /*
12661  * Determine the modified ACL for the new owner. This is only
12662  * necessary when the ACL is non-null.
12663  */
12664  aclDatum = SysCacheGetAttr(RELOID, tuple,
12665  Anum_pg_class_relacl,
12666  &isNull);
12667  if (!isNull)
12668  {
12669  newAcl = aclnewowner(DatumGetAclP(aclDatum),
12670  tuple_class->relowner, newOwnerId);
12671  repl_repl[Anum_pg_class_relacl - 1] = true;
12672  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
12673  }
12674 
12675  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
12676 
12677  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
12678 
12679  heap_freetuple(newtuple);
12680 
12681  /*
12682  * We must similarly update any per-column ACLs to reflect the new
12683  * owner; for neatness reasons that's split out as a subroutine.
12684  */
12685  change_owner_fix_column_acls(relationOid,
12686  tuple_class->relowner,
12687  newOwnerId);
12688 
12689  /*
12690  * Update owner dependency reference, if any. A composite type has
12691  * none, because it's tracked for the pg_type entry instead of here;
12692  * indexes and TOAST tables don't have their own entries either.
12693  */
12694  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
12695  tuple_class->relkind != RELKIND_INDEX &&
12696  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
12697  tuple_class->relkind != RELKIND_TOASTVALUE)
12698  changeDependencyOnOwner(RelationRelationId, relationOid,
12699  newOwnerId);
12700 
12701  /*
12702  * Also change the ownership of the table's row type, if it has one
12703  */
12704  if (OidIsValid(tuple_class->reltype))
12705  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
12706 
12707  /*
12708  * If we are operating on a table or materialized view, also change
12709  * the ownership of any indexes and sequences that belong to the
12710  * relation, as well as its toast table (if it has one).
12711  */
12712  if (tuple_class->relkind == RELKIND_RELATION ||
12713  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
12714  tuple_class->relkind == RELKIND_MATVIEW ||
12715  tuple_class->relkind == RELKIND_TOASTVALUE)
12716  {
12717  List *index_oid_list;
12718  ListCell *i;
12719 
12720  /* Find all the indexes belonging to this relation */
12721  index_oid_list = RelationGetIndexList(target_rel);
12722 
12723  /* For each index, recursively change its ownership */
12724  foreach(i, index_oid_list)
12725  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
12726 
12727  list_free(index_oid_list);
12728  }
12729 
12730  /* If it has a toast table, recurse to change its ownership */
12731  if (tuple_class->reltoastrelid != InvalidOid)
12732  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
12733  true, lockmode);
12734 
12735  /* If it has dependent sequences, recurse to change them too */
12736  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
12737  }
12738 
12739  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
12740 
12741  ReleaseSysCache(tuple);
12742  table_close(class_rel, RowExclusiveLock);
12743  relation_close(target_rel, NoLock);
12744 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int errhint(const char *fmt,...)
Definition: elog.c:1162
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:837
#define RelationGetDescr(relation)
Definition: rel.h:483
Oid GetUserId(void)
Definition: miscinit.c:476
#define DatumGetAclP(X)
Definition: acl.h:120
#define PointerGetDatum(X)
Definition: postgres.h:556
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1947
int errcode(int sqlerrcode)
Definition: elog.c:704
bool superuser(void)
Definition: superuser.c:46
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3836
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:698
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4625
signed int int32
Definition: c.h:417
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:313
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:45
#define ACL_CREATE
Definition: parsenodes.h:84
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3289
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:1048
#define RelationGetRelationName(relation)
Definition: rel.h:491
void check_is_member_of_role(Oid member, Oid role)
Definition: acl.c:4941
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:12515
#define WARNING
Definition: elog.h:40
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1388
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:155
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4687
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:302
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:12818
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4526
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:12753
int errmsg(const char *fmt,...)
Definition: elog.c:915
void list_free(List *list)
Definition: list.c:1376
#define elog(elevel,...)
Definition: elog.h:228
int i
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:669
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
Definition: pg_list.h:50
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1872
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1043
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ check_of_type()

void check_of_type ( HeapTuple  typetuple)

Definition at line 5990 of file tablecmds.c.

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

Referenced by ATExecAddOf(), and transformOfType().

5991 {
5992  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
5993  bool typeOk = false;
5994 
5995  if (typ->typtype == TYPTYPE_COMPOSITE)
5996  {
5997  Relation typeRelation;
5998 
5999  Assert(OidIsValid(typ->typrelid));
6000  typeRelation = relation_open(typ->typrelid, AccessShareLock);
6001  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6002 
6003  /*
6004  * Close the parent rel, but keep our AccessShareLock on it until xact
6005  * commit. That will prevent someone else from deleting or ALTERing
6006  * the type before the typed table creation/conversion commits.
6007  */
6008  relation_close(typeRelation, NoLock);
6009  }
6010  if (!typeOk)
6011  ereport(ERROR,
6012  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6013  errmsg("type %s is not a composite type",
6014  format_type_be(typ->oid))));
6015 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:704
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Form_pg_class rd_rel
Definition: rel.h:110
#define OidIsValid(objectId)
Definition: c.h:698
#define ERROR
Definition: elog.h:45
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
#define ereport(elevel,...)
Definition: elog.h:155
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:792
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
int errmsg(const char *fmt,...)
Definition: elog.c:915

◆ CheckTableNotInUse()

void CheckTableNotInUse ( Relation  rel,
const char *  stmt 
)

Definition at line 3594 of file tablecmds.c.

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

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

3595 {
3596  int expected_refcnt;
3597 
3598  expected_refcnt = rel->rd_isnailed ? 2 : 1;
3599  if (rel->rd_refcnt != expected_refcnt)
3600  ereport(ERROR,
3601  (errcode(ERRCODE_OBJECT_IN_USE),
3602  /* translator: first %s is a SQL command, eg ALTER TABLE */
3603  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
3604  stmt, RelationGetRelationName(rel))));
3605 
3606  if (rel->rd_rel->relkind != RELKIND_INDEX &&
3607  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
3609  ereport(ERROR,
3610  (errcode(ERRCODE_OBJECT_IN_USE),
3611  /* translator: first %s is a SQL command, eg ALTER TABLE */
3612  errmsg("cannot %s \"%s\" because it has pending trigger events",
3613  stmt, RelationGetRelationName(rel))));
3614 }
bool rd_isnailed
Definition: rel.h:61
int errcode(int sqlerrcode)
Definition: elog.c:704
Form_pg_class rd_rel
Definition: rel.h:110
#define ERROR
Definition: elog.h:45
#define RelationGetRelationName(relation)
Definition: rel.h:491
#define ereport(elevel,...)
Definition: elog.h:155
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5355
int errmsg(const char *fmt,...)
Definition: elog.c:915
int rd_refcnt
Definition: rel.h:58
#define RelationGetRelid(relation)
Definition: rel.h:457

◆ DefineRelation()

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

Definition at line 584 of file tablecmds.c.

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

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

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

◆ ExecuteTruncate()

void ExecuteTruncate ( TruncateStmt stmt)

Definition at line 1560 of file tablecmds.c.

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

Referenced by standard_ProcessUtility().

1561 {
1562  List *rels = NIL;
1563  List *relids = NIL;
1564  List *relids_logged = NIL;
1565  ListCell *cell;
1566 
1567  /*
1568  * Open, exclusive-lock, and check all the explicitly-specified relations
1569  */
1570  foreach(cell, stmt->relations)
1571  {
1572  RangeVar *rv = lfirst(cell);
1573  Relation rel;
1574  bool recurse = rv->inh;
1575  Oid myrelid;
1576  LOCKMODE lockmode = AccessExclusiveLock;
1577 
1578  myrelid = RangeVarGetRelidExtended(rv, lockmode,
1580  NULL);
1581 
1582  /* open the relation, we already hold a lock on it */
1583  rel = table_open(myrelid, NoLock);
1584 
1585  /* don't throw error for "TRUNCATE foo, foo" */
1586  if (list_member_oid(relids, myrelid))
1587  {
1588  table_close(rel, lockmode);
1589  continue;
1590  }
1591 
1592  /*
1593  * RangeVarGetRelidExtended() has done most checks with its callback,
1594  * but other checks with the now-opened Relation remain.
1595  */
1597 
1598  rels = lappend(rels, rel);
1599  relids = lappend_oid(relids, myrelid);
1600  /* Log this relation only if needed for logical decoding */
1601  if (RelationIsLogicallyLogged(rel))
1602  relids_logged = lappend_oid(relids_logged, myrelid);
1603 
1604  if (recurse)
1605  {
1606  ListCell *child;
1607  List *children;
1608 
1609  children = find_all_inheritors(myrelid, lockmode, NULL);
1610 
1611  foreach(child, children)
1612  {
1613  Oid childrelid = lfirst_oid(child);
1614 
1615  if (list_member_oid(relids, childrelid))
1616  continue;
1617 
1618  /* find_all_inheritors already got lock */
1619  rel = table_open(childrelid, NoLock);
1620 
1621  /*
1622  * It is possible that the parent table has children that are
1623  * temp tables of other backends. We cannot safely access
1624  * such tables (because of buffering issues), and the best
1625  * thing to do is to silently ignore them. Note that this
1626  * check is the same as one of the checks done in
1627  * truncate_check_activity() called below, still it is kept
1628  * here for simplicity.
1629  */
1630  if (RELATION_IS_OTHER_TEMP(rel))
1631  {
1632  table_close(rel, lockmode);
1633  continue;
1634  }
1635 
1636  /*
1637  * Inherited TRUNCATE commands perform access permission
1638  * checks on the parent table only. So we skip checking the
1639  * children's permissions and don't call
1640  * truncate_check_perms() here.
1641  */
1644 
1645  rels = lappend(rels, rel);
1646  relids = lappend_oid(relids, childrelid);
1647  /* Log this relation only if needed for logical decoding */
1648  if (RelationIsLogicallyLogged(rel))
1649  relids_logged = lappend_oid(relids_logged, childrelid);
1650  }
1651  }
1652  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1653  ereport(ERROR,
1654  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1655  errmsg("cannot truncate only a partitioned table"),
1656  errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1657  }
1658 
1659  ExecuteTruncateGuts(rels, relids, relids_logged,
1660  stmt->behavior, stmt->restart_seqs);
1661 
1662  /* And close the rels */
1663  foreach(cell, rels)
1664  {
1665  Relation rel = (Relation) lfirst(cell);
1666 
1667  table_close(rel, NoLock);
1668  }
1669 }
#define NIL
Definition: pg_list.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
int errhint(const char *fmt,...)
Definition: elog.c:1162
int LOCKMODE
Definition: lockdefs.h:26
static void RangeVarCallbackForTruncate(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:15636
int errcode(int sqlerrcode)
Definition: elog.c:704
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:636
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
DropBehavior behavior
Definition: parsenodes.h:2687
struct RelationData * Relation
Definition: relcache.h:27
#define ERROR
Definition: elog.h:45
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs)
Definition: tablecmds.c:1685
List * relations
Definition: parsenodes.h:2685
#define NoLock
Definition: lockdefs.h:34
bool restart_seqs
Definition: parsenodes.h:2686
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
bool inh
Definition: primnodes.h:69
List * lappend(List *list, void *datum)
Definition: list.c:321
#define ereport(elevel,...)
Definition: elog.h:155
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2028
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:674
#define lfirst(lc)
Definition: pg_list.h:169
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:594
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:1982
#define AccessExclusiveLock
Definition: lockdefs.h:45
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:165
int errmsg(const char *fmt,...)
Definition: elog.c:915
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:457
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ ExecuteTruncateGuts()

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

Definition at line 1685 of file tablecmds.c.

References AccessExclusiveLock, aclcheck_error(), ACLCHECK_NOT_OWNER, AfterTriggerBeginQuery(), AfterTriggerEndQuery(), Assert, CheckTableForSerializableConflictIn(), CreateExecutorState(), xl_heap_truncate::dbId, DROP_CASCADE, DROP_RESTRICT, ereport, errmsg(), EState::es_opened_result_relations, ExecASTruncateTriggers(), ExecBSTruncateTriggers(), xl_heap_truncate::flags, FreeExecutorState(), GetCurrentSubTransactionId(), getOwnedSequences(), GetUserId(), heap_truncate_check_FKs(), heap_truncate_find_FKs(), heap_truncate_one_rel(), i, InitResultRelInfo(), lappend(), lappend_oid(), lfirst, lfirst_oid, list_copy(), list_difference_ptr(), list_length(), MyDatabaseId, NIL, NoLock, NOTICE, xl_heap_truncate::nrelids, OBJECT_SEQUENCE, OidIsValid, palloc(), pg_class_ownercheck(), pgstat_count_truncate(), RelationData::rd_createSubid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_rel, REINDEX_REL_PROCESS_TOAST, reindex_relation(), relation_close(), relation_open(), RelationGetRelationName, RelationGetRelid, RelationIsLogicallyLogged, RelationSetNewRelfilenode(), OnCommitItem::relid, ResetSequence(), SizeOfHeapTruncate, table_close(), table_open(), truncate_check_activity(), truncate_check_perms(), truncate_check_rel(), XLH_TRUNCATE_CASCADE, XLH_TRUNCATE_RESTART_SEQS, XLOG_HEAP_TRUNCATE, XLOG_INCLUDE_ORIGIN, XLogBeginInsert(), XLogInsert(), XLogLogicalInfoActive, XLogRegisterData(), and XLogSetRecordFlags().

Referenced by apply_handle_truncate(), and ExecuteTruncate().

1687 {
1688  List *rels;
1689  List *seq_relids = NIL;
1690  EState *estate;
1691  ResultRelInfo *resultRelInfos;
1692  ResultRelInfo *resultRelInfo;
1693  SubTransactionId mySubid;
1694  ListCell *cell;
1695  Oid *logrelids;
1696 
1697  /*
1698  * Check the explicitly-specified relations.
1699  *
1700  * In CASCADE mode, suck in all referencing relations as well. This
1701  * requires multiple iterations to find indirectly-dependent relations. At
1702  * each phase, we need to exclusive-lock new rels before looking for their
1703  * dependencies, else we might miss something. Also, we check each rel as
1704  * soon as we open it, to avoid a faux pas such as holding lock for a long
1705  * time on a rel we have no permissions for.
1706  */
1707  rels = list_copy(explicit_rels);
1708  if (behavior == DROP_CASCADE)
1709  {
1710  for (;;)
1711  {
1712  List *newrelids;
1713 
1714  newrelids = heap_truncate_find_FKs(relids);
1715  if (newrelids == NIL)
1716  break; /* nothing else to add */
1717 
1718  foreach(cell, newrelids)
1719  {
1720  Oid relid = lfirst_oid(cell);
1721  Relation rel;
1722 
1723  rel = table_open(relid, AccessExclusiveLock);
1724  ereport(NOTICE,
1725  (errmsg("truncate cascades to table \"%s\"",
1726  RelationGetRelationName(rel))));
1727  truncate_check_rel(relid, rel->rd_rel);
1728  truncate_check_perms(relid, rel->rd_rel);
1730  rels = lappend(rels, rel);
1731  relids = lappend_oid(relids, relid);
1732  /* Log this relation only if needed for logical decoding */
1733  if (RelationIsLogicallyLogged(rel))
1734  relids_logged = lappend_oid(relids_logged, relid);
1735  }
1736  }
1737  }
1738 
1739  /*
1740  * Check foreign key references. In CASCADE mode, this should be
1741  * unnecessary since we just pulled in all the references; but as a
1742  * cross-check, do it anyway if in an Assert-enabled build.
1743  */
1744 #ifdef USE_ASSERT_CHECKING
1745  heap_truncate_check_FKs(rels, false);
1746 #else
1747  if (behavior == DROP_RESTRICT)
1748  heap_truncate_check_FKs(rels, false);
1749 #endif
1750 
1751  /*
1752  * If we are asked to restart sequences, find all the sequences, lock them
1753  * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1754  * We want to do this early since it's pointless to do all the truncation
1755  * work only to fail on sequence permissions.
1756  */
1757  if (restart_seqs)
1758  {
1759  foreach(cell, rels)
1760  {
1761  Relation rel = (Relation) lfirst(cell);
1762  List *seqlist = getOwnedSequences(RelationGetRelid(rel));
1763  ListCell *seqcell;
1764 
1765  foreach(seqcell, seqlist)
1766  {
1767  Oid seq_relid = lfirst_oid(seqcell);
1768  Relation seq_rel;
1769 
1770  seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1771 
1772  /* This check must match AlterSequence! */
1773  if (!pg_class_ownercheck(seq_relid, GetUserId()))
1775  RelationGetRelationName(seq_rel));
1776 
1777  seq_relids = lappend_oid(seq_relids, seq_relid);
1778 
1779  relation_close(seq_rel, NoLock);
1780  }
1781  }
1782  }
1783 
1784  /* Prepare to catch AFTER triggers. */
1786 
1787  /*
1788  * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1789  * each relation. We don't need to call ExecOpenIndices, though.
1790  *
1791  * We put the ResultRelInfos in the es_opened_result_relations list, even
1792  * though we don't have a range table and don't populate the
1793  * es_result_relations array. That's a bit bogus, but it's enough to make
1794  * ExecGetTriggerResultRel() find them.
1795  */
1796  estate = CreateExecutorState();
1797  resultRelInfos = (ResultRelInfo *)
1798  palloc(list_length(rels) * sizeof(ResultRelInfo));
1799  resultRelInfo = resultRelInfos;
1800  foreach(cell, rels)
1801  {
1802  Relation rel = (Relation) lfirst(cell);
1803 
1804  InitResultRelInfo(resultRelInfo,
1805  rel,
1806  0, /* dummy rangetable index */
1807  NULL,
1808  0);
1809  estate->es_opened_result_relations =
1810  lappend(estate->es_opened_result_relations, resultRelInfo);
1811  resultRelInfo++;
1812  }
1813 
1814  /*
1815  * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
1816  * truncating (this is because one of them might throw an error). Also, if
1817  * we were to allow them to prevent statement execution, that would need
1818  * to be handled here.
1819  */
1820  resultRelInfo = resultRelInfos;
1821  foreach(cell, rels)
1822  {
1823  ExecBSTruncateTriggers(estate, resultRelInfo);
1824  resultRelInfo++;
1825  }
1826 
1827  /*
1828  * OK, truncate each table.
1829  */
1830  mySubid = GetCurrentSubTransactionId();
1831 
1832  foreach(cell, rels)
1833  {
1834  Relation rel = (Relation) lfirst(cell);
1835 
1836  /* Skip partitioned tables as there is nothing to do */
1837  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1838  continue;
1839 
1840  /*
1841  * Normally, we need a transaction-safe truncation here. However, if
1842  * the table was either created in the current (sub)transaction or has
1843  * a new relfilenode in the current (sub)transaction, then we can just
1844  * truncate it in-place, because a rollback would cause the whole
1845  * table or the current physical file to be thrown away anyway.
1846  */
1847  if (rel->rd_createSubid == mySubid ||
1848  rel->rd_newRelfilenodeSubid == mySubid)
1849  {
1850  /* Immediate, non-rollbackable truncation is OK */
1851  heap_truncate_one_rel(rel);
1852  }
1853  else
1854  {
1855  Oid heap_relid;
1856  Oid toast_relid;
1857  ReindexParams reindex_params = {0};
1858 
1859  /*
1860  * This effectively deletes all rows in the table, and may be done
1861  * in a serializable transaction. In that case we must record a
1862  * rw-conflict in to this transaction from each transaction
1863  * holding a predicate lock on the table.
1864  */
1866 
1867  /*
1868  * Need the full transaction-safe pushups.
1869  *
1870  * Create a new empty storage file for the relation, and assign it
1871  * as the relfilenode value. The old storage file is scheduled for
1872  * deletion at commit.
1873  */
1874  RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence);
1875 
1876  heap_relid = RelationGetRelid(rel);
1877 
1878  /*
1879  * The same for the toast table, if any.
1880  */
1881  toast_relid = rel->rd_rel->reltoastrelid;
1882  if (OidIsValid(toast_relid))
1883  {
1884  Relation toastrel = relation_open(toast_relid,
1886 
1887  RelationSetNewRelfilenode(toastrel,
1888  toastrel->rd_rel->relpersistence);
1889  table_close(toastrel, NoLock);
1890  }
1891 
1892  /*
1893  * Reconstruct the indexes to match, and we're done.
1894  */
1896  &reindex_params);
1897  }
1898 
1899  pgstat_count_truncate(rel);
1900  }
1901 
1902  /*
1903  * Restart owned sequences if we were asked to.
1904  */
1905  foreach(cell, seq_relids)
1906  {
1907  Oid seq_relid = lfirst_oid(cell);
1908 
1909  ResetSequence(seq_relid);
1910  }
1911 
1912  /*
1913  * Write a WAL record to allow this set of actions to be logically
1914  * decoded.
1915  *
1916  * Assemble an array of relids so we can write a single WAL record for the
1917  * whole action.
1918  */
1919  if (list_length(relids_logged) > 0)
1920  {
1921  xl_heap_truncate xlrec;
1922  int i = 0;
1923 
1924  /* should only get here if wal_level >= logical */
1926 
1927  logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
1928  foreach(cell, relids_logged)
1929  logrelids[i++] = lfirst_oid(cell);
1930 
1931  xlrec.dbId = MyDatabaseId;
1932  xlrec.nrelids = list_length(relids_logged);
1933  xlrec.flags = 0;
1934  if (behavior == DROP_CASCADE)
1935  xlrec.flags |= XLH_TRUNCATE_CASCADE;
1936  if (restart_seqs)
1938 
1939  XLogBeginInsert();
1940  XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
1941  XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
1942 
1944 
1945  (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
1946  }
1947 
1948  /*
1949  * Process all AFTER STATEMENT TRUNCATE triggers.
1950  */
1951  resultRelInfo = resultRelInfos;
1952  foreach(cell, rels)
1953  {
1954  ExecASTruncateTriggers(estate, resultRelInfo);
1955  resultRelInfo++;
1956  }
1957 
1958  /* Handle queued AFTER triggers */
1959  AfterTriggerEndQuery(estate);
1960 
1961  /* We can clean up the EState now */
1962  FreeExecutorState(estate);
1963 
1964  /*
1965  * Close any rels opened by CASCADE (can't do this while EState still
1966  * holds refs)
1967  */
1968  rels = list_difference_ptr(rels, explicit_rels);
1969  foreach(cell, rels)
1970  {
1971  Relation rel = (Relation) lfirst(cell);
1972 
1973  table_close(rel, NoLock);
1974  }
1975 }
#define NIL
Definition: pg_list.h:65
#define XLH_TRUNCATE_CASCADE
Definition: heapam_xlog.h:120
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, Relation partition_root, int instrument_options)
Definition: execMain.c:1196
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Oid GetUserId(void)
Definition: miscinit.c:476
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3341
List * list_difference_ptr(const List *list1, const List *list2)
Definition: list.c:1102
List * list_copy(const List *oldlist)
Definition: list.c:1403
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3385
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:104
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:238
uint32 SubTransactionId
Definition: c.h:579
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:636
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
static void truncate_check_perms(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2010
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
#define OidIsValid(objectId)
Definition: c.h:698
void RelationSetNewRelfilenode(Relation relation, char persistence)
Definition: relcache.c:3600
void FreeExecutorState(EState *estate)
Definition: execUtils.c:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
struct RelationData * Relation
Definition: relcache.h:27
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2943
#define XLogLogicalInfoActive()
Definition: xlog.h:208
struct ResultRelInfo ResultRelInfo
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
List * es_opened_result_relations
Definition: execnodes.h:537
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2990
#define RelationGetRelationName(relation)
Definition: rel.h:491
void pgstat_count_truncate(Relation rel)
Definition: pgstat.c:2276
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:404
EState * CreateExecutorState(void)
Definition: execUtils.c:89
List * lappend(List *list, void *datum)
Definition: list.c:321
SubTransactionId rd_createSubid
Definition: rel.h:103
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:945
Oid MyDatabaseId
Definition: globals.c:86
#define XLH_TRUNCATE_RESTART_SEQS
Definition: heapam_xlog.h:121
#define XLOG_HEAP_TRUNCATE
Definition: heapam_xlog.h:35
#define ereport(elevel,...)
Definition: elog.h:155
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2028
#define NOTICE
Definition: elog.h:37
void AfterTriggerBeginQuery(void)
Definition: trigger.c:4500
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:792
#define lfirst(lc)
Definition: pg_list.h:169
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4687
#define SizeOfHeapTruncate
Definition: heapam_xlog.h:136
static int list_length(const List *l)
Definition: pg_list.h:149
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4529
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:1982
bool reindex_relation(Oid relid, int flags, ReindexParams *params)
Definition: index.c:3849
#define AccessExclusiveLock
Definition: lockdefs.h:45
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:4520
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:915
int i
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:155
void ResetSequence(Oid seq_relid)
Definition: sequence.c:270
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
void XLogBeginInsert(void)
Definition: xloginsert.c:123
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:457
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3480
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ find_composite_type_dependencies()

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

Definition at line 5823 of file tablecmds.c.

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

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

5825 {
5826  Relation depRel;
5827  ScanKeyData key[2];
5828  SysScanDesc depScan;
5829  HeapTuple depTup;
5830 
5831  /* since this function recurses, it could be driven to stack overflow */
5833 
5834  /*
5835  * We scan pg_depend to find those things that depend on the given type.
5836  * (We assume we can ignore refobjsubid for a type.)
5837  */
5838  depRel = table_open(DependRelationId, AccessShareLock);
5839 
5840  ScanKeyInit(&key[0],
5841  Anum_pg_depend_refclassid,
5842  BTEqualStrategyNumber, F_OIDEQ,
5843  ObjectIdGetDatum(TypeRelationId));
5844  ScanKeyInit(&key[1],
5845  Anum_pg_depend_refobjid,
5846  BTEqualStrategyNumber, F_OIDEQ,
5847  ObjectIdGetDatum(typeOid));
5848 
5849  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
5850  NULL, 2, key);
5851 
5852  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
5853  {
5854  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
5855  Relation rel;
5856  Form_pg_attribute att;
5857 
5858  /* Check for directly dependent types */
5859  if (pg_depend->classid == TypeRelationId)
5860  {
5861  /*
5862  * This must be an array, domain, or range containing the given
5863  * type, so recursively check for uses of this type. Note that
5864  * any error message will mention the original type not the
5865  * container; this is intentional.
5866  */
5867  find_composite_type_dependencies(pg_depend->objid,
5868  origRelation, origTypeName);
5869  continue;
5870  }
5871 
5872  /* Else, ignore dependees that aren't user columns of relations */
5873  /* (we assume system columns are never of interesting types) */
5874  if (pg_depend->classid != RelationRelationId ||
5875  pg_depend->objsubid <= 0)
5876  continue;
5877 
5878  rel = relation_open(pg_depend->objid, AccessShareLock);
5879  att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
5880 
5881  if (rel->rd_rel->relkind == RELKIND_RELATION ||
5882  rel->rd_rel->relkind == RELKIND_MATVIEW ||
5883  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5884  {
5885  if (origTypeName)
5886  ereport(ERROR,
5887  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5888  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5889  origTypeName,
5891  NameStr(att->attname))));
5892  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
5893  ereport(ERROR,
5894  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5895  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5896  RelationGetRelationName(origRelation),
5898  NameStr(att->attname))));
5899  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
5900  ereport(ERROR,
5901  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5902  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
5903  RelationGetRelationName(origRelation),
5905  NameStr(att->attname))));
5906  else
5907  ereport(ERROR,
5908  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5909  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
5910  RelationGetRelationName(origRelation),
5912  NameStr(att->attname))));
5913  }
5914  else if (OidIsValid(rel->rd_rel->reltype))
5915  {
5916  /*
5917  * A view or composite type itself isn't a problem, but we must
5918  * recursively check for indirect dependencies via its rowtype.
5919  */
5921  origRelation, origTypeName);
5922  }
5923 
5925  }
5926 
5927  systable_endscan(depScan);
5928 
5930 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:593
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:5823
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:704
Form_pg_class rd_rel
Definition: rel.h:110
#define OidIsValid(objectId)
Definition: c.h:698
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:381
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:500
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:45
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
void check_stack_depth(void)
Definition: postgres.c:3377
#define RelationGetRelationName(relation)
Definition: rel.h:491
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:74
#define DependReferenceIndexId
Definition: pg_depend.h:81
TupleDesc rd_att
Definition: rel.h:111
#define ereport(elevel,...)
Definition: elog.h:155
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define NameStr(name)
Definition: c.h:669
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ PartConstraintImpliedByRelConstraint()

bool PartConstraintImpliedByRelConstraint ( Relation  scanrel,
List partConstraint 
)

Definition at line 16147 of file tablecmds.c.

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

Referenced by check_default_partition_contents(), and QueuePartitionConstraintValidation().

16149 {
16150  List *existConstraint = NIL;
16151  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
16152  int i;
16153 
16154  if (constr && constr->has_not_null)
16155  {
16156  int natts = scanrel->rd_att->natts;
16157 
16158  for (i = 1; i <= natts; i++)
16159  {
16160  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
16161 
16162  if (att->attnotnull && !att->attisdropped)
16163  {
16164  NullTest *ntest = makeNode(NullTest);
16165 
16166  ntest->arg = (Expr *) makeVar(1,
16167  i,
16168  att->atttypid,
16169  att->atttypmod,
16170  att->attcollation,
16171  0);
16172  ntest->nulltesttype = IS_NOT_NULL;
16173 
16174  /*
16175  * argisrow=false is correct even for a composite column,
16176  * because attnotnull does not represent a SQL-spec IS NOT
16177  * NULL test in such a case, just IS DISTINCT FROM NULL.
16178  */
16179  ntest->argisrow = false;
16180  ntest->location = -1;
16181  existConstraint = lappend(existConstraint, ntest);
16182  }
16183  }
16184  }
16185 
16186  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
16187 }
#define NIL
Definition: pg_list.h:65
#define RelationGetDescr(relation)
Definition: rel.h:483
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Expr * arg
Definition: primnodes.h:1243
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
List * lappend(List *list, void *datum)
Definition: list.c:321
TupleDesc rd_att
Definition: rel.h:111
NullTestType nulltesttype
Definition: primnodes.h:1244
#define makeNode(_type_)
Definition: nodes.h:576
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:16200
int location
Definition: primnodes.h:1246
int i
bool argisrow
Definition: primnodes.h:1245
bool has_not_null
Definition: tupdesc.h:44
Definition: pg_list.h:50

◆ PreCommit_on_commit_actions()

void PreCommit_on_commit_actions ( void  )

Definition at line 15437 of file tablecmds.c.

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

Referenced by CommitTransaction(), and PrepareTransaction().

15438 {
15439  ListCell *l;
15440  List *oids_to_truncate = NIL;
15441  List *oids_to_drop = NIL;
15442 
15443  foreach(l, on_commits)
15444  {
15445  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
15446 
15447  /* Ignore entry if already dropped in this xact */
15449  continue;
15450 
15451  switch (oc->oncommit)
15452  {
15453  case ONCOMMIT_NOOP:
15455  /* Do nothing (there shouldn't be such entries, actually) */
15456  break;
15457  case ONCOMMIT_DELETE_ROWS:
15458 
15459  /*
15460  * If this transaction hasn't accessed any temporary
15461  * relations, we can skip truncating ON COMMIT DELETE ROWS
15462  * tables, as they must still be empty.
15463  */
15465  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
15466  break;
15467  case ONCOMMIT_DROP:
15468  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
15469  break;
15470  }
15471  }
15472 
15473  /*
15474  * Truncate relations before dropping so that all dependencies between
15475  * relations are removed after they are worked on. Doing it like this
15476  * might be a waste as it is possible that a relation being truncated will
15477  * be dropped anyway due to its parent being dropped, but this makes the
15478  * code more robust because of not having to re-check that the relation
15479  * exists at truncation time.
15480  */
15481  if (oids_to_truncate != NIL)
15482  heap_truncate(oids_to_truncate);
15483 
15484  if (oids_to_drop != NIL)
15485  {
15486  ObjectAddresses *targetObjects = new_object_addresses();
15487  ListCell *l;
15488 
15489  foreach(l, oids_to_drop)
15490  {
15491  ObjectAddress object;
15492 
15493  object.classId = RelationRelationId;
15494  object.objectId = lfirst_oid(l);
15495  object.objectSubId = 0;
15496 
15497  Assert(!object_address_present(&object, targetObjects));
15498 
15499  add_exact_object_address(&object, targetObjects);
15500  }
15501 
15502  /*
15503  * Since this is an automatic drop, rather than one directly initiated
15504  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
15505  */
15506  performMultipleDeletions(targetObjects, DROP_CASCADE,
15508 
15509 #ifdef USE_ASSERT_CHECKING
15510 
15511  /*
15512  * Note that table deletion will call remove_on_commit_action, so the
15513  * entry should get marked as deleted.
15514  */
15515  foreach(l, on_commits)
15516  {
15517  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
15518 
15519  if (oc->oncommit != ONCOMMIT_DROP)
15520  continue;
15521 
15523  }
15524 #endif
15525  }
15526 }
#define NIL
Definition: pg_list.h:65
OnCommitAction oncommit
Definition: tablecmds.c:108
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2670
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2610
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2555
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
static List * on_commits
Definition: tablecmds.c:121
int MyXactFlags
Definition: xact.c:132
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:102
SubTransactionId deleting_subid
Definition: tablecmds.c:118
#define Assert(condition)
Definition: c.h:792
#define lfirst(lc)
Definition: pg_list.h:169
#define PERFORM_DELETION_QUIETLY
Definition: dependency.h:143
void heap_truncate(List *relids)
Definition: heap.c:3300
#define InvalidSubTransactionId
Definition: c.h:581
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:372
Definition: pg_list.h:50
#define lfirst_oid(lc)
Definition: pg_list.h:171
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:141

◆ RangeVarCallbackOwnsRelation()

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

Definition at line 15660 of file tablecmds.c.

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

Referenced by AlterSequence(), and ProcessUtilitySlow().

15662 {
15663  HeapTuple tuple;
15664 
15665  /* Nothing to do if the relation was not found. */
15666  if (!OidIsValid(relId))
15667  return;
15668 
15669  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
15670  if (!HeapTupleIsValid(tuple)) /* should not happen */
15671  elog(ERROR, "cache lookup failed for relation %u", relId);
15672 
15673  if (!pg_class_ownercheck(relId, GetUserId()))
15675  relation->relname);
15676 
15677  if (!allowSystemTableMods &&
15678  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
15679  ereport(ERROR,
15680  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
15681  errmsg("permission denied: \"%s\" is a system catalog",
15682  relation->relname)));
15683 
15684  ReleaseSysCache(tuple);
15685 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Oid GetUserId(void)
Definition: miscinit.c:476
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1947
int errcode(int sqlerrcode)
Definition: elog.c:704
#define OidIsValid(objectId)
Definition: c.h:698
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:78
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:45
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
bool allowSystemTableMods
Definition: globals.c:121
#define ereport(elevel,...)
Definition: elog.h:155
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4687
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define elog(elevel,...)
Definition: elog.h:228
ObjectType get_relkind_objtype(char relkind)

◆ RangeVarCallbackOwnsTable()

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

Definition at line 15604 of file tablecmds.c.

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

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

15606 {
15607  char relkind;
15608 
15609  /* Nothing to do if the relation was not found. */
15610  if (!OidIsValid(relId))
15611  return;
15612 
15613  /*
15614  * If the relation does exist, check whether it's an index. But note that
15615  * the relation might have been dropped between the time we did the name
15616  * lookup and now. In that case, there's nothing to do.
15617  */
15618  relkind = get_rel_relkind(relId);
15619  if (!relkind)
15620  return;
15621  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
15622  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
15623  ereport(ERROR,
15624  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15625  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
15626 
15627  /* Check permissions */
15628  if (!pg_class_ownercheck(relId, GetUserId()))
15630 }
Oid GetUserId(void)
Definition: miscinit.c:476
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1947
int errcode(int sqlerrcode)
Definition: elog.c:704
#define OidIsValid(objectId)
Definition: c.h:698
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ERROR
Definition: elog.h:45
#define ereport(elevel,...)
Definition: elog.h:155
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4687
int errmsg(const char *fmt,...)
Definition: elog.c:915
ObjectType get_relkind_objtype(char relkind)

◆ register_on_commit_action()

void register_on_commit_action ( Oid  relid,
OnCommitAction  action 
)

Definition at line 15378 of file tablecmds.c.

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

Referenced by heap_create_with_catalog().

15379 {
15380  OnCommitItem *oc;
15381  MemoryContext oldcxt;
15382 
15383  /*
15384  * We needn't bother registering the relation unless there is an ON COMMIT
15385  * action we need to take.
15386  */
15388  return;
15389 
15391 
15392  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
15393  oc->relid = relid;
15394  oc->oncommit = action;
15397 
15398  /*
15399  * We use lcons() here so that ON COMMIT actions are processed in reverse
15400  * order of registration. That might not be essential but it seems
15401  * reasonable.
15402  */
15403  on_commits = lcons(oc, on_commits);
15404 
15405  MemoryContextSwitchTo(oldcxt);
15406 }
OnCommitAction oncommit
Definition: tablecmds.c:108
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
SubTransactionId creating_subid
Definition: tablecmds.c:117
static List * on_commits
Definition: tablecmds.c:121
SubTransactionId deleting_subid
Definition: tablecmds.c:118
List * lcons(void *datum, List *list)
Definition: list.c:453
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
#define InvalidSubTransactionId
Definition: c.h:581
void * palloc(Size size)
Definition: mcxt.c:950
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ remove_on_commit_action()

void remove_on_commit_action ( Oid  relid)

Definition at line 15414 of file tablecmds.c.

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

Referenced by heap_drop_with_catalog().

15415 {
15416  ListCell *l;
15417 
15418  foreach(l, on_commits)
15419  {
15420  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
15421 
15422  if (oc->relid == relid)
15423  {
15425  break;
15426  }
15427  }
15428 }
static List * on_commits
Definition: tablecmds.c:121
SubTransactionId deleting_subid
Definition: tablecmds.c:118
#define lfirst(lc)
Definition: pg_list.h:169
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723

◆ RemoveRelations()

void RemoveRelations ( DropStmt drop)

Definition at line 1259 of file tablecmds.c.

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

Referenced by ExecDropStmt().

1260 {
1261  ObjectAddresses *objects;
1262  char relkind;
1263  ListCell *cell;
1264  int flags = 0;
1265  LOCKMODE lockmode = AccessExclusiveLock;
1266 
1267  /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1268  if (drop->concurrent)
1269  {
1270  /*
1271  * Note that for temporary relations this lock may get upgraded later
1272  * on, but as no other session can access a temporary relation, this
1273  * is actually fine.
1274  */
1275  lockmode = ShareUpdateExclusiveLock;
1276  Assert(drop->removeType == OBJECT_INDEX);
1277  if (list_length(drop->objects) != 1)
1278  ereport(ERROR,
1279  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1280  errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1281  if (drop->behavior == DROP_CASCADE)
1282  ereport(ERROR,
1283  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1284  errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1285  }
1286 
1287  /*
1288  * First we identify all the relations, then we delete them in a single
1289  * performMultipleDeletions() call. This is to avoid unwanted DROP
1290  * RESTRICT errors if one of the relations depends on another.
1291  */
1292 
1293  /* Determine required relkind */
1294  switch (drop->removeType)
1295  {
1296  case OBJECT_TABLE:
1297  relkind = RELKIND_RELATION;
1298  break;
1299 
1300  case OBJECT_INDEX:
1301  relkind = RELKIND_INDEX;
1302  break;
1303 
1304  case OBJECT_SEQUENCE:
1305  relkind = RELKIND_SEQUENCE;
1306  break;
1307 
1308  case OBJECT_VIEW:
1309  relkind = RELKIND_VIEW;
1310  break;
1311 
1312  case OBJECT_MATVIEW:
1313  relkind = RELKIND_MATVIEW;
1314  break;
1315 
1316  case OBJECT_FOREIGN_TABLE:
1317  relkind = RELKIND_FOREIGN_TABLE;
1318  break;
1319 
1320  default:
1321  elog(ERROR, "unrecognized drop object type: %d",
1322  (int) drop->removeType);
1323  relkind = 0; /* keep compiler quiet */
1324  break;
1325  }
1326 
1327  /* Lock and validate each relation; build a list of object addresses */
1328  objects = new_object_addresses();
1329 
1330  foreach(cell, drop->objects)
1331  {
1332  RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1333  Oid relOid;
1334  ObjectAddress obj;
1336 
1337  /*
1338  * These next few steps are a great deal like relation_openrv, but we
1339  * don't bother building a relcache entry since we don't need it.
1340  *
1341  * Check for shared-cache-inval messages before trying to access the
1342  * relation. This is needed to cover the case where the name
1343  * identifies a rel that has been dropped and recreated since the
1344  * start of our transaction: if we don't flush the old syscache entry,
1345  * then we'll latch onto that entry and suffer an error later.
1346  */
1348 
1349  /* Look up the appropriate relation using namespace search. */
1350  state.relkind = relkind;
1351  state.heapOid = InvalidOid;
1352  state.partParentOid = InvalidOid;
1353  state.concurrent = drop->concurrent;
1354  relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1356  (void *) &state);
1357 
1358  /* Not there? */
1359  if (!OidIsValid(relOid))
1360  {
1361  DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1362  continue;
1363  }
1364 
1365  /*
1366  * Decide if concurrent mode needs to be used here or not. The
1367  * relation persistence cannot be known without its OID.
1368  */
1369  if (drop->concurrent &&
1370  get_rel_persistence(relOid) != RELPERSISTENCE_TEMP)
1371  {
1372  Assert(list_length(drop->objects) == 1 &&
1373  drop->removeType == OBJECT_INDEX);
1375  }
1376 
1377  /*
1378  * Concurrent index drop cannot be used with partitioned indexes,
1379  * either.
1380  */
1381  if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1382  get_rel_relkind(relOid) == RELKIND_PARTITIONED_INDEX)
1383  ereport(ERROR,
1384  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1385  errmsg("cannot drop partitioned index \"%s\" concurrently",
1386  rel->relname)));
1387 
1388  /* OK, we're ready to delete this one */
1389  obj.classId = RelationRelationId;
1390  obj.objectId = relOid;
1391  obj.objectSubId = 0;
1392 
1393  add_exact_object_address(&obj, objects);
1394  }
1395 
1396  performMultipleDeletions(objects, drop->behavior, flags);
1397 
1398  free_object_addresses(objects);
1399 }
void AcceptInvalidationMessages(void)
Definition: inval.c:687
int LOCKMODE
Definition: lockdefs.h:26
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1947
List * objects
Definition: parsenodes.h:2671
bool missing_ok
Definition: parsenodes.h:2674
int errcode(int sqlerrcode)
Definition: elog.c:704
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3061
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2610
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2555
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2851
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:698
ObjectType removeType
Definition: parsenodes.h:2672
#define PERFORM_DELETION_CONCURRENTLY
Definition: dependency.h:142
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:45
bool concurrent
Definition: parsenodes.h:2675
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
DropBehavior behavior
Definition: parsenodes.h:2673
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:1408
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:155
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define Assert(condition)
Definition: c.h:792
#define lfirst(lc)
Definition: pg_list.h:169
Definition: regguts.h:298
static int list_length(const List *l)
Definition: pg_list.h:149
char get_rel_persistence(Oid relid)
Definition: lsyscache.c:2022
#define AccessExclusiveLock
Definition: lockdefs.h:45
static void DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
Definition: tablecmds.c:1184
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define elog(elevel,...)
Definition: elog.h:228
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:372
Definition: pg_list.h:50

◆ renameatt()

ObjectAddress renameatt ( RenameStmt stmt)

Definition at line 3257 of file tablecmds.c.

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

Referenced by ExecRenameStmt().

3258 {
3259  Oid relid;
3261  ObjectAddress address;
3262 
3263  /* lock level taken here should match renameatt_internal */
3265  stmt->missing_ok ? RVR_MISSING_OK : 0,
3267  NULL);
3268 
3269  if (!OidIsValid(relid))
3270  {
3271  ereport(NOTICE,
3272  (errmsg("relation \"%s\" does not exist, skipping",
3273  stmt->relation->relname)));
3274  return InvalidObjectAddress;
3275  }
3276 
3277  attnum =
3278  renameatt_internal(relid,
3279  stmt->subname, /* old att name */
3280  stmt->newname, /* new att name */
3281  stmt->relation->inh, /* recursive? */
3282  false, /* recursing? */
3283  0, /* expected inhcount */
3284  stmt->behavior);
3285 
3286  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3287 
3288  return address;
3289 }
char * subname
Definition: parsenodes.h:2938
char * newname
Definition: parsenodes.h:2940
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:698
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2942
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:2936
int16 attnum
Definition: pg_attribute.h:79
#define ereport(elevel,...)
Definition: elog.h:155
#define NOTICE
Definition: elog.h:37
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3237
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:3092
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:915
DropBehavior behavior
Definition: parsenodes.h:2941
int16 AttrNumber
Definition: attnum.h:21

◆ RenameConstraint()

ObjectAddress RenameConstraint ( RenameStmt stmt)

Definition at line 3401 of file tablecmds.c.

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

Referenced by ExecRenameStmt().

3402 {
3403  Oid relid = InvalidOid;
3404  Oid typid = InvalidOid;
3405 
3406  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3407  {
3408  Relation rel;
3409  HeapTuple tup;
3410 
3412  rel = table_open(TypeRelationId, RowExclusiveLock);
3413  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3414  if (!HeapTupleIsValid(tup))
3415  elog(ERROR, "cache lookup failed for type %u", typid);
3416  checkDomainOwner(tup);
3417  ReleaseSysCache(tup);
3418  table_close(rel, NoLock);
3419  }
3420  else
3421  {
3422  /* lock level taken here should match rename_constraint_internal */
3424  stmt->missing_ok ? RVR_MISSING_OK : 0,
3426  NULL);
3427  if (!OidIsValid(relid))
3428  {
3429  ereport(NOTICE,
3430  (errmsg("relation \"%s\" does not exist, skipping",
3431  stmt->relation->relname)));
3432  return InvalidObjectAddress;
3433  }
3434  }
3435 
3436  return
3437  rename_constraint_internal(relid, typid,
3438  stmt->subname,
3439  stmt->newname,
3440  (stmt->relation &&
3441  stmt->relation->inh), /* recursive? */
3442  false, /* recursing? */
3443  0 /* expected inhcount */ );
3444 
3445 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
char * subname
Definition: parsenodes.h:2938
ObjectType renameType
Definition: parsenodes.h:2934
#define castNode(_type_, nodeptr)
Definition: nodes.h:597
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:3295
char * newname
Definition: parsenodes.h:2940
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:698
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2942
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:45
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Node * object
Definition: parsenodes.h:2937
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
bool inh
Definition: primnodes.h:69
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
RangeVar * relation
Definition: parsenodes.h:2936
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:155
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3237
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3436
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define elog(elevel,...)
Definition: elog.h:228
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:456
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ RenameRelation()

ObjectAddress RenameRelation ( RenameStmt stmt)

Definition at line 3452 of file tablecmds.c.

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

Referenced by ExecRenameStmt().

3453 {
3454  bool is_index = stmt->renameType == OBJECT_INDEX;
3455  Oid relid;
3456  ObjectAddress address;
3457 
3458  /*
3459  * Grab an exclusive lock on the target table, index, sequence, view,
3460  * materialized view, or foreign table, which we will NOT release until
3461  * end of transaction.
3462  *
3463  * Lock level used here should match RenameRelationInternal, to avoid lock
3464  * escalation.
3465  */
3466  relid = RangeVarGetRelidExtended(stmt->relation,
3468  stmt->missing_ok ? RVR_MISSING_OK : 0,
3470  (void *) stmt);
3471 
3472  if (!OidIsValid(relid))
3473  {
3474  ereport(NOTICE,
3475  (errmsg("relation \"%s\" does not exist, skipping",
3476  stmt->relation->relname)));
3477  return InvalidObjectAddress;
3478  }
3479 
3480  /* Do the work */
3481  RenameRelationInternal(relid, stmt->newname, false, is_index);
3482 
3483  ObjectAddressSet(address, RelationRelationId, relid);
3484 
3485  return address;
3486 }
ObjectType renameType
Definition: parsenodes.h:2934
char * newname
Definition: parsenodes.h:2940
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:698
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2942
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:15692
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
RangeVar * relation
Definition: parsenodes.h:2936
#define ereport(elevel,...)
Definition: elog.h:155
#define NOTICE
Definition: elog.h:37
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:915
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3492

◆ RenameRelationInternal()

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

Definition at line 3492 of file tablecmds.c.

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

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

3493 {
3494  Relation targetrelation;
3495  Relation relrelation; /* for RELATION relation */
3496  HeapTuple reltup;
3497  Form_pg_class relform;
3498  Oid namespaceId;
3499 
3500  /*
3501  * Grab a lock on the target relation, which we will NOT release until end
3502  * of transaction. We need at least a self-exclusive lock so that
3503  * concurrent DDL doesn't overwrite the rename if they start updating
3504  * while still seeing the old version. The lock also guards against
3505  * triggering relcache reloads in concurrent sessions, which might not
3506  * handle this information changing under them. For indexes, we can use a
3507  * reduced lock level because RelationReloadIndexInfo() handles indexes
3508  * specially.
3509  */
3510  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
3511  namespaceId = RelationGetNamespace(targetrelation);
3512 
3513  /*
3514  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3515  */
3516  relrelation = table_open(RelationRelationId, RowExclusiveLock);
3517 
3518  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3519  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3520  elog(ERROR, "cache lookup failed for relation %u", myrelid);
3521  relform = (Form_pg_class) GETSTRUCT(reltup);
3522 
3523  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3524  ereport(ERROR,
3525  (errcode(ERRCODE_DUPLICATE_TABLE),
3526  errmsg("relation \"%s\" already exists",
3527  newrelname)));
3528 
3529  /*
3530  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
3531  * because it's a copy...)
3532  */
3533  namestrcpy(&(relform->relname), newrelname);
3534 
3535  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3536 
3537  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
3538  InvalidOid, is_internal);
3539 
3540  heap_freetuple(reltup);
3541  table_close(relrelation, RowExclusiveLock);
3542 
3543  /*
3544  * Also rename the associated type, if any.
3545  */
3546  if (OidIsValid(targetrelation->rd_rel->reltype))
3547  RenameTypeInternal(targetrelation->rd_rel->reltype,
3548  newrelname, namespaceId);
3549 
3550  /*
3551  * Also rename the associated constraint, if any.
3552  */
3553  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3554  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3555  {
3556  Oid constraintId = get_index_constraint(myrelid);
3557 
3558  if (OidIsValid(constraintId))
3559  RenameConstraintById(constraintId, newrelname);
3560  }
3561 
3562  /*
3563  * Close rel, but keep lock!
3564  */
3565  relation_close(targetrelation, NoLock);
3566 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
void namestrcpy(Name name, const char *str)
Definition: name.c:233
int errcode(int sqlerrcode)
Definition: elog.c:704
Form_pg_class rd_rel
Definition: rel.h:110
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:698
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
Definition: objectaccess.h:178
void RenameConstraintById(Oid conId, const char *newname)
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:45
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1829
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:978
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:793
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:155
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:302
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define elog(elevel,...)
Definition: elog.h:228
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetNamespace(relation)
Definition: rel.h:498

◆ SetRelationHasSubclass()

void SetRelationHasSubclass ( Oid  relationId,
bool  relhassubclass 
)

Definition at line 3010 of file tablecmds.c.

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

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

3011 {
3012  Relation relationRelation;
3013  HeapTuple tuple;
3014  Form_pg_class classtuple;
3015 
3016  /*
3017  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3018  */
3019  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3020  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3021  if (!HeapTupleIsValid(tuple))
3022  elog(ERROR, "cache lookup failed for relation %u", relationId);
3023  classtuple = (Form_pg_class) GETSTRUCT(tuple);
3024 
3025  if (classtuple->relhassubclass != relhassubclass)
3026  {
3027  classtuple->relhassubclass = relhassubclass;
3028  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3029  }
3030  else
3031  {
3032  /* no need to change tuple, but force relcache rebuild anyway */
3034  }
3035 
3036  heap_freetuple(tuple);
3037  table_close(relationRelation, RowExclusiveLock);
3038 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:45
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:302
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
#define elog(elevel,...)
Definition: elog.h:228
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1314
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39