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

15043 {
15044  HeapTuple classTup;
15045  Form_pg_class classForm;
15046  ObjectAddress thisobj;
15047  bool already_done = false;
15048 
15049  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
15050  if (!HeapTupleIsValid(classTup))
15051  elog(ERROR, "cache lookup failed for relation %u", relOid);
15052  classForm = (Form_pg_class) GETSTRUCT(classTup);
15053 
15054  Assert(classForm->relnamespace == oldNspOid);
15055 
15056  thisobj.classId = RelationRelationId;
15057  thisobj.objectId = relOid;
15058  thisobj.objectSubId = 0;
15059 
15060  /*
15061  * If the object has already been moved, don't move it again. If it's
15062  * already in the right place, don't move it, but still fire the object
15063  * access hook.
15064  */
15065  already_done = object_address_present(&thisobj, objsMoved);
15066  if (!already_done && oldNspOid != newNspOid)
15067  {
15068  /* check for duplicate name (more friendly than unique-index failure) */
15069  if (get_relname_relid(NameStr(classForm->relname),
15070  newNspOid) != InvalidOid)
15071  ereport(ERROR,
15072  (errcode(ERRCODE_DUPLICATE_TABLE),
15073  errmsg("relation \"%s\" already exists in schema \"%s\"",
15074  NameStr(classForm->relname),
15075  get_namespace_name(newNspOid))));
15076 
15077  /* classTup is a copy, so OK to scribble on */
15078  classForm->relnamespace = newNspOid;
15079 
15080  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
15081 
15082  /* Update dependency on schema if caller said so */
15083  if (hasDependEntry &&
15084  changeDependencyFor(RelationRelationId,
15085  relOid,
15086  NamespaceRelationId,
15087  oldNspOid,
15088  newNspOid) != 1)
15089  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
15090  NameStr(classForm->relname));
15091  }
15092  if (!already_done)
15093  {
15094  add_exact_object_address(&thisobj, objsMoved);
15095 
15096  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
15097  }
15098 
15099  heap_freetuple(classTup);
15100 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2533
int errcode(int sqlerrcode)
Definition: elog.c:610
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2473
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1748
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3155
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:738
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
int errmsg(const char *fmt,...)
Definition: elog.c:824
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:346
#define elog(elevel,...)
Definition: elog.h:214
#define NameStr(name)
Definition: c.h:615

◆ AlterTable()

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

Definition at line 3617 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3619 {
3620  Relation rel;
3621 
3622  /* Caller is required to provide an adequate lock. */
3623  rel = relation_open(context->relid, NoLock);
3624 
3625  CheckTableNotInUse(rel, "ALTER TABLE");
3626 
3627  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
3628 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:3952
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:3533
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1777

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 3691 of file tablecmds.c.

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

3692 {
3693  /*
3694  * This only works if we read catalog tables using MVCC snapshots.
3695  */
3696  ListCell *lcmd;
3698 
3699  foreach(lcmd, cmds)
3700  {
3701  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3702  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
3703 
3704  switch (cmd->subtype)
3705  {
3706  /*
3707  * These subcommands rewrite the heap, so require full locks.
3708  */
3709  case AT_AddColumn: /* may rewrite heap, in some cases and visible
3710  * to SELECT */
3711  case AT_SetTableSpace: /* must rewrite heap */
3712  case AT_AlterColumnType: /* must rewrite heap */
3713  cmd_lockmode = AccessExclusiveLock;
3714  break;
3715 
3716  /*
3717  * These subcommands may require addition of toast tables. If
3718  * we add a toast table to a table currently being scanned, we
3719  * might miss data added to the new toast table by concurrent
3720  * insert transactions.
3721  */
3722  case AT_SetStorage: /* may add toast tables, see
3723  * ATRewriteCatalogs() */
3724  cmd_lockmode = AccessExclusiveLock;
3725  break;
3726 
3727  /*
3728  * Removing constraints can affect SELECTs that have been
3729  * optimized assuming the constraint holds true. See also
3730  * CloneFkReferenced.
3731  */
3732  case AT_DropConstraint: /* as DROP INDEX */
3733  case AT_DropNotNull: /* may change some SQL plans */
3734  cmd_lockmode = AccessExclusiveLock;
3735  break;
3736 
3737  /*
3738  * Subcommands that may be visible to concurrent SELECTs
3739  */
3740  case AT_DropColumn: /* change visible to SELECT */
3741  case AT_AddColumnToView: /* CREATE VIEW */
3742  case AT_DropOids: /* used to equiv to DropColumn */
3743  case AT_EnableAlwaysRule: /* may change SELECT rules */
3744  case AT_EnableReplicaRule: /* may change SELECT rules */
3745  case AT_EnableRule: /* may change SELECT rules */
3746  case AT_DisableRule: /* may change SELECT rules */
3747  cmd_lockmode = AccessExclusiveLock;
3748  break;
3749 
3750  /*
3751  * Changing owner may remove implicit SELECT privileges
3752  */
3753  case AT_ChangeOwner: /* change visible to SELECT */
3754  cmd_lockmode = AccessExclusiveLock;
3755  break;
3756 
3757  /*
3758  * Changing foreign table options may affect optimization.
3759  */
3760  case AT_GenericOptions:
3762  cmd_lockmode = AccessExclusiveLock;
3763  break;
3764 
3765  /*
3766  * These subcommands affect write operations only.
3767  */
3768  case AT_EnableTrig:
3769  case AT_EnableAlwaysTrig:
3770  case AT_EnableReplicaTrig:
3771  case AT_EnableTrigAll:
3772  case AT_EnableTrigUser:
3773  case AT_DisableTrig:
3774  case AT_DisableTrigAll:
3775  case AT_DisableTrigUser:
3776  cmd_lockmode = ShareRowExclusiveLock;
3777  break;
3778 
3779  /*
3780  * These subcommands affect write operations only. XXX
3781  * Theoretically, these could be ShareRowExclusiveLock.
3782  */
3783  case AT_ColumnDefault:
3784  case AT_AlterConstraint:
3785  case AT_AddIndex: /* from ADD CONSTRAINT */
3786  case AT_AddIndexConstraint:
3787  case AT_ReplicaIdentity:
3788  case AT_SetNotNull:
3789  case AT_EnableRowSecurity:
3790  case AT_DisableRowSecurity:
3791  case AT_ForceRowSecurity:
3792  case AT_NoForceRowSecurity:
3793  case AT_AddIdentity:
3794  case AT_DropIdentity:
3795  case AT_SetIdentity:
3796  case AT_DropExpression:
3797  cmd_lockmode = AccessExclusiveLock;
3798  break;
3799 
3800  case AT_AddConstraint:
3801  case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
3802  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
3803  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
3804  if (IsA(cmd->def, Constraint))
3805  {
3806  Constraint *con = (Constraint *) cmd->def;
3807 
3808  switch (con->contype)
3809  {
3810  case CONSTR_EXCLUSION:
3811  case CONSTR_PRIMARY:
3812  case CONSTR_UNIQUE:
3813 
3814  /*
3815  * Cases essentially the same as CREATE INDEX. We
3816  * could reduce the lock strength to ShareLock if
3817  * we can work out how to allow concurrent catalog
3818  * updates. XXX Might be set down to
3819  * ShareRowExclusiveLock but requires further
3820  * analysis.
3821  */
3822  cmd_lockmode = AccessExclusiveLock;
3823  break;
3824  case CONSTR_FOREIGN:
3825 
3826  /*
3827  * We add triggers to both tables when we add a
3828  * Foreign Key, so the lock level must be at least
3829  * as strong as CREATE TRIGGER.
3830  */
3831  cmd_lockmode = ShareRowExclusiveLock;
3832  break;
3833 
3834  default:
3835  cmd_lockmode = AccessExclusiveLock;
3836  }
3837  }
3838  break;
3839 
3840  /*
3841  * These subcommands affect inheritance behaviour. Queries
3842  * started before us will continue to see the old inheritance
3843  * behaviour, while queries started after we commit will see
3844  * new behaviour. No need to prevent reads or writes to the
3845  * subtable while we hook it up though. Changing the TupDesc
3846  * may be a problem, so keep highest lock.
3847  */
3848  case AT_AddInherit:
3849  case AT_DropInherit:
3850  cmd_lockmode = AccessExclusiveLock;
3851  break;
3852 
3853  /*
3854  * These subcommands affect implicit row type conversion. They
3855  * have affects similar to CREATE/DROP CAST on queries. don't
3856  * provide for invalidating parse trees as a result of such
3857  * changes, so we keep these at AccessExclusiveLock.
3858  */
3859  case AT_AddOf:
3860  case AT_DropOf:
3861  cmd_lockmode = AccessExclusiveLock;
3862  break;
3863 
3864  /*
3865  * Only used by CREATE OR REPLACE VIEW which must conflict
3866  * with an SELECTs currently using the view.
3867  */
3868  case AT_ReplaceRelOptions:
3869  cmd_lockmode = AccessExclusiveLock;
3870  break;
3871 
3872  /*
3873  * These subcommands affect general strategies for performance
3874  * and maintenance, though don't change the semantic results
3875  * from normal data reads and writes. Delaying an ALTER TABLE
3876  * behind currently active writes only delays the point where
3877  * the new strategy begins to take effect, so there is no
3878  * benefit in waiting. In this case the minimum restriction
3879  * applies: we don't currently allow concurrent catalog
3880  * updates.
3881  */
3882  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
3883  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
3884  case AT_DropCluster: /* Uses MVCC in getIndexes() */
3885  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
3886  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
3887  cmd_lockmode = ShareUpdateExclusiveLock;
3888  break;
3889 
3890  case AT_SetLogged:
3891  case AT_SetUnLogged:
3892  cmd_lockmode = AccessExclusiveLock;
3893  break;
3894 
3895  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
3896  cmd_lockmode = ShareUpdateExclusiveLock;
3897  break;
3898 
3899  /*
3900  * Rel options are more complex than first appears. Options
3901  * are set here for tables, views and indexes; for historical
3902  * reasons these can all be used with ALTER TABLE, so we can't
3903  * decide between them using the basic grammar.
3904  */
3905  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
3906  * getTables() */
3907  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
3908  * getTables() */
3909  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
3910  break;
3911 
3912  case AT_AttachPartition:
3913  cmd_lockmode = ShareUpdateExclusiveLock;
3914  break;
3915 
3916  case AT_DetachPartition:
3917  cmd_lockmode = AccessExclusiveLock;
3918  break;
3919 
3920  case AT_CheckNotNull:
3921 
3922  /*
3923  * This only examines the table's schema; but lock must be
3924  * strong enough to prevent concurrent DROP NOT NULL.
3925  */
3926  cmd_lockmode = AccessShareLock;
3927  break;
3928 
3929  default: /* oops */
3930  elog(ERROR, "unrecognized alter table type: %d",
3931  (int) cmd->subtype);
3932  break;
3933  }
3934 
3935  /*
3936  * Take the greatest lockmode from any subcommand
3937  */
3938  if (cmd_lockmode > lockmode)
3939  lockmode = cmd_lockmode;
3940  }
3941 
3942  return lockmode;
3943 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
int LOCKMODE
Definition: lockdefs.h:26
#define AccessShareLock
Definition: lockdefs.h:36
AlterTableType subtype
Definition: parsenodes.h:1863
#define ERROR
Definition: elog.h:43
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define lfirst(lc)
Definition: pg_list.h:190
#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:214
ConstrType contype
Definition: parsenodes.h:2152
Definition: pg_list.h:50

◆ AlterTableInternal()

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

Definition at line 3646 of file tablecmds.c.

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

3647 {
3648  Relation rel;
3649  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
3650 
3651  rel = relation_open(relid, lockmode);
3652 
3654 
3655  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
3656 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:3952
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:3691
void EventTriggerAlterTableRelid(Oid objectId)

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3561 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3562 {
3563  return RangeVarGetRelidExtended(stmt->relation, lockmode,
3564  stmt->missing_ok ? RVR_MISSING_OK : 0,
3566  (void *) stmt);
3567 }
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:15553
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
RangeVar * relation
Definition: parsenodes.h:1777

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 13234 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().

13235 {
13236  List *relations = NIL;
13237  ListCell *l;
13238  ScanKeyData key[1];
13239  Relation rel;
13240  TableScanDesc scan;
13241  HeapTuple tuple;
13242  Oid orig_tablespaceoid;
13243  Oid new_tablespaceoid;
13244  List *role_oids = roleSpecsToIds(stmt->roles);
13245 
13246  /* Ensure we were not asked to move something we can't */
13247  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
13248  stmt->objtype != OBJECT_MATVIEW)
13249  ereport(ERROR,
13250  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13251  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
13252 
13253  /* Get the orig and new tablespace OIDs */
13254  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
13255  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
13256 
13257  /* Can't move shared relations in to or out of pg_global */
13258  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
13259  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
13260  new_tablespaceoid == GLOBALTABLESPACE_OID)
13261  ereport(ERROR,
13262  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13263  errmsg("cannot move relations in to or out of pg_global tablespace")));
13264 
13265  /*
13266  * Must have CREATE rights on the new tablespace, unless it is the
13267  * database default tablespace (which all users implicitly have CREATE
13268  * rights on).
13269  */
13270  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
13271  {
13272  AclResult aclresult;
13273 
13274  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
13275  ACL_CREATE);
13276  if (aclresult != ACLCHECK_OK)
13277  aclcheck_error(aclresult, OBJECT_TABLESPACE,
13278  get_tablespace_name(new_tablespaceoid));
13279  }
13280 
13281  /*
13282  * Now that the checks are done, check if we should set either to
13283  * InvalidOid because it is our database's default tablespace.
13284  */
13285  if (orig_tablespaceoid == MyDatabaseTableSpace)
13286  orig_tablespaceoid = InvalidOid;
13287 
13288  if (new_tablespaceoid == MyDatabaseTableSpace)
13289  new_tablespaceoid = InvalidOid;
13290 
13291  /* no-op */
13292  if (orig_tablespaceoid == new_tablespaceoid)
13293  return new_tablespaceoid;
13294 
13295  /*
13296  * Walk the list of objects in the tablespace and move them. This will
13297  * only find objects in our database, of course.
13298  */
13299  ScanKeyInit(&key[0],
13300  Anum_pg_class_reltablespace,
13301  BTEqualStrategyNumber, F_OIDEQ,
13302  ObjectIdGetDatum(orig_tablespaceoid));
13303 
13304  rel = table_open(RelationRelationId, AccessShareLock);
13305  scan = table_beginscan_catalog(rel, 1, key);
13306  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
13307  {
13308  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
13309  Oid relOid = relForm->oid;
13310 
13311  /*
13312  * Do not move objects in pg_catalog as part of this, if an admin
13313  * really wishes to do so, they can issue the individual ALTER
13314  * commands directly.
13315  *
13316  * Also, explicitly avoid any shared tables, temp tables, or TOAST
13317  * (TOAST will be moved with the main table).
13318  */
13319  if (IsCatalogNamespace(relForm->relnamespace) ||
13320  relForm->relisshared ||
13321  isAnyTempNamespace(relForm->relnamespace) ||
13322  IsToastNamespace(relForm->relnamespace))
13323  continue;
13324 
13325  /* Only move the object type requested */
13326  if ((stmt->objtype == OBJECT_TABLE &&
13327  relForm->relkind != RELKIND_RELATION &&
13328  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
13329  (stmt->objtype == OBJECT_INDEX &&
13330  relForm->relkind != RELKIND_INDEX &&
13331  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
13332  (stmt->objtype == OBJECT_MATVIEW &&
13333  relForm->relkind != RELKIND_MATVIEW))
13334  continue;
13335 
13336  /* Check if we are only moving objects owned by certain roles */
13337  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
13338  continue;
13339 
13340  /*
13341  * Handle permissions-checking here since we are locking the tables
13342  * and also to avoid doing a bunch of work only to fail part-way. Note
13343  * that permissions will also be checked by AlterTableInternal().
13344  *
13345  * Caller must be considered an owner on the table to move it.
13346  */
13347  if (!pg_class_ownercheck(relOid, GetUserId()))
13349  NameStr(relForm->relname));
13350 
13351  if (stmt->nowait &&
13353  ereport(ERROR,
13354  (errcode(ERRCODE_OBJECT_IN_USE),
13355  errmsg("aborting because lock on relation \"%s.%s\" is not available",
13356  get_namespace_name(relForm->relnamespace),
13357  NameStr(relForm->relname))));
13358  else
13360 
13361  /* Add to our list of objects to move */
13362  relations = lappend_oid(relations, relOid);
13363  }
13364 
13365  table_endscan(scan);
13367 
13368  if (relations == NIL)
13369  ereport(NOTICE,
13370  (errcode(ERRCODE_NO_DATA_FOUND),
13371  errmsg("no matching relations in tablespace \"%s\" found",
13372  orig_tablespaceoid == InvalidOid ? "(database default)" :
13373  get_tablespace_name(orig_tablespaceoid))));
13374 
13375  /* Everything is locked, loop through and move all of the relations. */
13376  foreach(l, relations)
13377  {
13378  List *cmds = NIL;
13380 
13381  cmd->subtype = AT_SetTableSpace;
13382  cmd->name = stmt->new_tablespacename;
13383 
13384  cmds = lappend(cmds, cmd);
13385 
13387  /* OID is set by AlterTableInternal */
13388  AlterTableInternal(lfirst_oid(l), cmds, false);
13390  }
13391 
13392  return new_tablespaceoid;
13393 }
#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:1416
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4670
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:98
Oid GetUserId(void)
Definition: miscinit.c:448
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1866
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:529
int errcode(int sqlerrcode)
Definition: elog.c:610
AlterTableType subtype
Definition: parsenodes.h:1863
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:195
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:644
Oid MyDatabaseTableSpace
Definition: globals.c:87
void EventTriggerAlterTableStart(Node *parsetree)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3327
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3155
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1275
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:144
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:577
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1434
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:4720
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:177
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:862
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:3646
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:824
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1462
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:615
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3195
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:192
void EventTriggerAlterTableEnd(void)

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 14930 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().

14931 {
14932  Relation rel;
14933  Oid relid;
14934  Oid oldNspOid;
14935  Oid nspOid;
14936  RangeVar *newrv;
14937  ObjectAddresses *objsMoved;
14938  ObjectAddress myself;
14939 
14941  stmt->missing_ok ? RVR_MISSING_OK : 0,
14943  (void *) stmt);
14944 
14945  if (!OidIsValid(relid))
14946  {
14947  ereport(NOTICE,
14948  (errmsg("relation \"%s\" does not exist, skipping",
14949  stmt->relation->relname)));
14950  return InvalidObjectAddress;
14951  }
14952 
14953  rel = relation_open(relid, NoLock);
14954 
14955  oldNspOid = RelationGetNamespace(rel);
14956 
14957  /* If it's an owned sequence, disallow moving it by itself. */
14958  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
14959  {
14960  Oid tableId;
14961  int32 colId;
14962 
14963  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
14964  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
14965  ereport(ERROR,
14966  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14967  errmsg("cannot move an owned sequence into another schema"),
14968  errdetail("Sequence \"%s\" is linked to table \"%s\".",
14970  get_rel_name(tableId))));
14971  }
14972 
14973  /* Get and lock schema OID and check its permissions. */
14974  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
14975  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
14976 
14977  /* common checks on switching namespaces */
14978  CheckSetNamespace(oldNspOid, nspOid);
14979 
14980  objsMoved = new_object_addresses();
14981  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
14982  free_object_addresses(objsMoved);
14983 
14984  ObjectAddressSet(myself, RelationRelationId, relid);
14985 
14986  if (oldschema)
14987  *oldschema = oldNspOid;
14988 
14989  /* close rel, but keep lock until commit */
14990  relation_close(rel, NoLock);
14991 
14992  return myself;
14993 }
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:755
int errcode(int sqlerrcode)
Definition: elog.c:610
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2418
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2713
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
signed int int32
Definition: c.h:355
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:43
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15001
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:15553
int errdetail(const char *fmt,...)
Definition: elog.c:957
#define RelationGetRelationName(relation)
Definition: rel.h:490
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:2967
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:534
#define ereport(elevel,...)
Definition: elog.h:144
#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:824
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1791
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:420
#define RelationGetNamespace(relation)
Definition: rel.h:497

◆ AlterTableNamespaceInternal()

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

Definition at line 15001 of file tablecmds.c.

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

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

15003 {
15004  Relation classRel;
15005 
15006  Assert(objsMoved != NULL);
15007 
15008  /* OK, modify the pg_class row and pg_depend entry */
15009  classRel = table_open(RelationRelationId, RowExclusiveLock);
15010 
15011  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
15012  nspOid, true, objsMoved);
15013 
15014  /* Fix the table's row type too */
15015  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
15016  nspOid, false, false, objsMoved);
15017 
15018  /* Fix other dependent stuff */
15019  if (rel->rd_rel->relkind == RELKIND_RELATION ||
15020  rel->rd_rel->relkind == RELKIND_MATVIEW ||
15021  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15022  {
15023  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
15024  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
15025  objsMoved, AccessExclusiveLock);
15026  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
15027  false, objsMoved);
15028  }
15029 
15030  table_close(classRel, RowExclusiveLock);
15031 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3510
Form_pg_class rd_rel
Definition: rel.h:109
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15109
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:15154
#define RowExclusiveLock
Definition: lockdefs.h:38
#define Assert(condition)
Definition: c.h:738
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15039
#define AccessExclusiveLock
Definition: lockdefs.h:45
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:456

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 15430 of file tablecmds.c.

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

15432 {
15433  ListCell *cur_item;
15434 
15435  foreach(cur_item, on_commits)
15436  {
15437  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
15438 
15439  if (!isCommit && oc->creating_subid == mySubid)
15440  {
15441  /* cur_item must be removed */
15443  pfree(oc);
15444  }
15445  else
15446  {
15447  /* cur_item must be preserved */
15448  if (oc->creating_subid == mySubid)
15449  oc->creating_subid = parentSubid;
15450  if (oc->deleting_subid == mySubid)
15451  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
15452  }
15453  }
15454 }
SubTransactionId creating_subid
Definition: tablecmds.c:118
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:368
void pfree(void *pointer)
Definition: mcxt.c:1056
static List * on_commits
Definition: tablecmds.c:122
SubTransactionId deleting_subid
Definition: tablecmds.c:119
#define lfirst(lc)
Definition: pg_list.h:190
#define InvalidSubTransactionId
Definition: c.h:519

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 15398 of file tablecmds.c.

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

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

15399 {
15400  ListCell *cur_item;
15401 
15402  foreach(cur_item, on_commits)
15403  {
15404  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
15405 
15406  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
15408  {
15409  /* cur_item must be removed */
15411  pfree(oc);
15412  }
15413  else
15414  {
15415  /* cur_item must be preserved */
15418  }
15419  }
15420 }
SubTransactionId creating_subid
Definition: tablecmds.c:118
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:368
void pfree(void *pointer)
Definition: mcxt.c:1056
static List * on_commits
Definition: tablecmds.c:122
SubTransactionId deleting_subid
Definition: tablecmds.c:119
#define lfirst(lc)
Definition: pg_list.h:190
#define InvalidSubTransactionId
Definition: c.h:519

◆ ATExecChangeOwner()

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

Definition at line 12380 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, 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().

12381 {
12382  Relation target_rel;
12383  Relation class_rel;
12384  HeapTuple tuple;
12385  Form_pg_class tuple_class;
12386 
12387  /*
12388  * Get exclusive lock till end of transaction on the target table. Use
12389  * relation_open so that we can work on indexes and sequences.
12390  */
12391  target_rel = relation_open(relationOid, lockmode);
12392 
12393  /* Get its pg_class tuple, too */
12394  class_rel = table_open(RelationRelationId, RowExclusiveLock);
12395 
12396  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
12397  if (!HeapTupleIsValid(tuple))
12398  elog(ERROR, "cache lookup failed for relation %u", relationOid);
12399  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
12400 
12401  /* Can we change the ownership of this tuple? */
12402  switch (tuple_class->relkind)
12403  {
12404  case RELKIND_RELATION:
12405  case RELKIND_VIEW:
12406  case RELKIND_MATVIEW:
12407  case RELKIND_FOREIGN_TABLE:
12408  case RELKIND_PARTITIONED_TABLE:
12409  /* ok to change owner */
12410  break;
12411  case RELKIND_INDEX:
12412  if (!recursing)
12413  {
12414  /*
12415  * Because ALTER INDEX OWNER used to be allowed, and in fact
12416  * is generated by old versions of pg_dump, we give a warning
12417  * and do nothing rather than erroring out. Also, to avoid
12418  * unnecessary chatter while restoring those old dumps, say
12419  * nothing at all if the command would be a no-op anyway.
12420  */
12421  if (tuple_class->relowner != newOwnerId)
12422  ereport(WARNING,
12423  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12424  errmsg("cannot change owner of index \"%s\"",
12425  NameStr(tuple_class->relname)),
12426  errhint("Change the ownership of the index's table, instead.")));
12427  /* quick hack to exit via the no-op path */
12428  newOwnerId = tuple_class->relowner;
12429  }
12430  break;
12431  case RELKIND_PARTITIONED_INDEX:
12432  if (recursing)
12433  break;
12434  ereport(ERROR,
12435  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12436  errmsg("cannot change owner of index \"%s\"",
12437  NameStr(tuple_class->relname)),
12438  errhint("Change the ownership of the index's table, instead.")));
12439  break;
12440  case RELKIND_SEQUENCE:
12441  if (!recursing &&
12442  tuple_class->relowner != newOwnerId)
12443  {
12444  /* if it's an owned sequence, disallow changing it by itself */
12445  Oid tableId;
12446  int32 colId;
12447 
12448  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
12449  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
12450  ereport(ERROR,
12451  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12452  errmsg("cannot change owner of sequence \"%s\"",
12453  NameStr(tuple_class->relname)),
12454  errdetail("Sequence \"%s\" is linked to table \"%s\".",
12455  NameStr(tuple_class->relname),
12456  get_rel_name(tableId))));
12457  }
12458  break;
12459  case RELKIND_COMPOSITE_TYPE:
12460  if (recursing)
12461  break;
12462  ereport(ERROR,
12463  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12464  errmsg("\"%s\" is a composite type",
12465  NameStr(tuple_class->relname)),
12466  errhint("Use ALTER TYPE instead.")));
12467  break;
12468  case RELKIND_TOASTVALUE:
12469  if (recursing)
12470  break;
12471  /* FALL THRU */
12472  default:
12473  ereport(ERROR,
12474  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12475  errmsg("\"%s\" is not a table, view, sequence, or foreign table",
12476  NameStr(tuple_class->relname))));
12477  }
12478 
12479  /*
12480  * If the new owner is the same as the existing owner, consider the
12481  * command to have succeeded. This is for dump restoration purposes.
12482  */
12483  if (tuple_class->relowner != newOwnerId)
12484  {
12485  Datum repl_val[Natts_pg_class];
12486  bool repl_null[Natts_pg_class];
12487  bool repl_repl[Natts_pg_class];
12488  Acl *newAcl;
12489  Datum aclDatum;
12490  bool isNull;
12491  HeapTuple newtuple;
12492 
12493  /* skip permission checks when recursing to index or toast table */
12494  if (!recursing)
12495  {
12496  /* Superusers can always do it */
12497  if (!superuser())
12498  {
12499  Oid namespaceOid = tuple_class->relnamespace;
12500  AclResult aclresult;
12501 
12502  /* Otherwise, must be owner of the existing object */
12503  if (!pg_class_ownercheck(relationOid, GetUserId()))
12505  RelationGetRelationName(target_rel));
12506 
12507  /* Must be able to become new owner */
12508  check_is_member_of_role(GetUserId(), newOwnerId);
12509 
12510  /* New owner must have CREATE privilege on namespace */
12511  aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
12512  ACL_CREATE);
12513  if (aclresult != ACLCHECK_OK)
12514  aclcheck_error(aclresult, OBJECT_SCHEMA,
12515  get_namespace_name(namespaceOid));
12516  }
12517  }
12518 
12519  memset(repl_null, false, sizeof(repl_null));
12520  memset(repl_repl, false, sizeof(repl_repl));
12521 
12522  repl_repl[Anum_pg_class_relowner - 1] = true;
12523  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
12524 
12525  /*
12526  * Determine the modified ACL for the new owner. This is only
12527  * necessary when the ACL is non-null.
12528  */
12529  aclDatum = SysCacheGetAttr(RELOID, tuple,
12530  Anum_pg_class_relacl,
12531  &isNull);
12532  if (!isNull)
12533  {
12534  newAcl = aclnewowner(DatumGetAclP(aclDatum),
12535  tuple_class->relowner, newOwnerId);
12536  repl_repl[Anum_pg_class_relacl - 1] = true;
12537  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
12538  }
12539 
12540  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
12541 
12542  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
12543 
12544  heap_freetuple(newtuple);
12545 
12546  /*
12547  * We must similarly update any per-column ACLs to reflect the new
12548  * owner; for neatness reasons that's split out as a subroutine.
12549  */
12550  change_owner_fix_column_acls(relationOid,
12551  tuple_class->relowner,
12552  newOwnerId);
12553 
12554  /*
12555  * Update owner dependency reference, if any. A composite type has
12556  * none, because it's tracked for the pg_type entry instead of here;
12557  * indexes and TOAST tables don't have their own entries either.
12558  */
12559  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
12560  tuple_class->relkind != RELKIND_INDEX &&
12561  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
12562  tuple_class->relkind != RELKIND_TOASTVALUE)
12563  changeDependencyOnOwner(RelationRelationId, relationOid,
12564  newOwnerId);
12565 
12566  /*
12567  * Also change the ownership of the table's row type, if it has one
12568  */
12569  if (tuple_class->relkind != RELKIND_INDEX &&
12570  tuple_class->relkind != RELKIND_PARTITIONED_INDEX)
12571  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
12572 
12573  /*
12574  * If we are operating on a table or materialized view, also change
12575  * the ownership of any indexes and sequences that belong to the
12576  * relation, as well as its toast table (if it has one).
12577  */
12578  if (tuple_class->relkind == RELKIND_RELATION ||
12579  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
12580  tuple_class->relkind == RELKIND_MATVIEW ||
12581  tuple_class->relkind == RELKIND_TOASTVALUE)
12582  {
12583  List *index_oid_list;
12584  ListCell *i;
12585 
12586  /* Find all the indexes belonging to this relation */
12587  index_oid_list = RelationGetIndexList(target_rel);
12588 
12589  /* For each index, recursively change its ownership */
12590  foreach(i, index_oid_list)
12591  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
12592 
12593  list_free(index_oid_list);
12594  }
12595 
12596  /* If it has a toast table, recurse to change its ownership */
12597  if (tuple_class->reltoastrelid != InvalidOid)
12598  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
12599  true, lockmode);
12600 
12601  /* If it has dependent sequences, recurse to change them too */
12602  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
12603  }
12604 
12605  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
12606 
12607  ReleaseSysCache(tuple);
12608  table_close(class_rel, RowExclusiveLock);
12609  relation_close(target_rel, NoLock);
12610 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int errhint(const char *fmt,...)
Definition: elog.c:1071
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:755
#define RelationGetDescr(relation)
Definition: rel.h:482
Oid GetUserId(void)
Definition: miscinit.c:448
#define DatumGetAclP(X)
Definition: acl.h:120
#define PointerGetDatum(X)
Definition: postgres.h:556
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1866
int errcode(int sqlerrcode)
Definition: elog.c:610
bool superuser(void)
Definition: superuser.c:46
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3380
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4658
signed int int32
Definition: c.h:355
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:309
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3327
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#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:3155
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:957
#define RelationGetRelationName(relation)
Definition: rel.h:490
void check_is_member_of_role(Oid member, Oid role)
Definition: acl.c:4938
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:12380
#define WARNING
Definition: elog.h:40
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1377
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#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:4720
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:12684
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4506
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:12619
int errmsg(const char *fmt,...)
Definition: elog.c:824
void list_free(List *list)
Definition: list.c:1376
#define elog(elevel,...)
Definition: elog.h:214
int i
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:615
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:1791
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1044
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ check_of_type()

void check_of_type ( HeapTuple  typetuple)

Definition at line 5887 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().

5888 {
5889  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
5890  bool typeOk = false;
5891 
5892  if (typ->typtype == TYPTYPE_COMPOSITE)
5893  {
5894  Relation typeRelation;
5895 
5896  Assert(OidIsValid(typ->typrelid));
5897  typeRelation = relation_open(typ->typrelid, AccessShareLock);
5898  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
5899 
5900  /*
5901  * Close the parent rel, but keep our AccessShareLock on it until xact
5902  * commit. That will prevent someone else from deleting or ALTERing
5903  * the type before the typed table creation/conversion commits.
5904  */
5905  relation_close(typeRelation, NoLock);
5906  }
5907  if (!typeOk)
5908  ereport(ERROR,
5909  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5910  errmsg("type %s is not a composite type",
5911  format_type_be(typ->oid))));
5912 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:327
Form_pg_class rd_rel
Definition: rel.h:109
#define OidIsValid(objectId)
Definition: c.h:644
#define ERROR
Definition: elog.h:43
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
#define ereport(elevel,...)
Definition: elog.h:144
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:738
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ CheckTableNotInUse()

void CheckTableNotInUse ( Relation  rel,
const char *  stmt 
)

Definition at line 3533 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().

3534 {
3535  int expected_refcnt;
3536 
3537  expected_refcnt = rel->rd_isnailed ? 2 : 1;
3538  if (rel->rd_refcnt != expected_refcnt)
3539  ereport(ERROR,
3540  (errcode(ERRCODE_OBJECT_IN_USE),
3541  /* translator: first %s is a SQL command, eg ALTER TABLE */
3542  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
3543  stmt, RelationGetRelationName(rel))));
3544 
3545  if (rel->rd_rel->relkind != RELKIND_INDEX &&
3546  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
3548  ereport(ERROR,
3549  (errcode(ERRCODE_OBJECT_IN_USE),
3550  /* translator: first %s is a SQL command, eg ALTER TABLE */
3551  errmsg("cannot %s \"%s\" because it has pending trigger events",
3552  stmt, RelationGetRelationName(rel))));
3553 }
bool rd_isnailed
Definition: rel.h:61
int errcode(int sqlerrcode)
Definition: elog.c:610
Form_pg_class rd_rel
Definition: rel.h:109
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:490
#define ereport(elevel,...)
Definition: elog.h:144
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5287
int errmsg(const char *fmt,...)
Definition: elog.c:824
int rd_refcnt
Definition: rel.h:58
#define RelationGetRelid(relation)
Definition: rel.h:456

◆ DefineRelation()

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

Definition at line 581 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(), StrNCpy, 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().

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

◆ ExecuteTruncate()

void ExecuteTruncate ( TruncateStmt stmt)

Definition at line 1546 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().

1547 {
1548  List *rels = NIL;
1549  List *relids = NIL;
1550  List *relids_logged = NIL;
1551  ListCell *cell;
1552 
1553  /*
1554  * Open, exclusive-lock, and check all the explicitly-specified relations
1555  */
1556  foreach(cell, stmt->relations)
1557  {
1558  RangeVar *rv = lfirst(cell);
1559  Relation rel;
1560  bool recurse = rv->inh;
1561  Oid myrelid;
1562  LOCKMODE lockmode = AccessExclusiveLock;
1563 
1564  myrelid = RangeVarGetRelidExtended(rv, lockmode,
1566  NULL);
1567 
1568  /* open the relation, we already hold a lock on it */
1569  rel = table_open(myrelid, NoLock);
1570 
1571  /* don't throw error for "TRUNCATE foo, foo" */
1572  if (list_member_oid(relids, myrelid))
1573  {
1574  table_close(rel, lockmode);
1575  continue;
1576  }
1577 
1578  /*
1579  * RangeVarGetRelidExtended() has done most checks with its callback,
1580  * but other checks with the now-opened Relation remain.
1581  */
1583 
1584  rels = lappend(rels, rel);
1585  relids = lappend_oid(relids, myrelid);
1586  /* Log this relation only if needed for logical decoding */
1587  if (RelationIsLogicallyLogged(rel))
1588  relids_logged = lappend_oid(relids_logged, myrelid);
1589 
1590  if (recurse)
1591  {
1592  ListCell *child;
1593  List *children;
1594 
1595  children = find_all_inheritors(myrelid, lockmode, NULL);
1596 
1597  foreach(child, children)
1598  {
1599  Oid childrelid = lfirst_oid(child);
1600 
1601  if (list_member_oid(relids, childrelid))
1602  continue;
1603 
1604  /* find_all_inheritors already got lock */
1605  rel = table_open(childrelid, NoLock);
1606 
1607  /*
1608  * It is possible that the parent table has children that are
1609  * temp tables of other backends. We cannot safely access
1610  * such tables (because of buffering issues), and the best
1611  * thing to do is to silently ignore them. Note that this
1612  * check is the same as one of the checks done in
1613  * truncate_check_activity() called below, still it is kept
1614  * here for simplicity.
1615  */
1616  if (RELATION_IS_OTHER_TEMP(rel))
1617  {
1618  table_close(rel, lockmode);
1619  continue;
1620  }
1621 
1622  /*
1623  * Inherited TRUNCATE commands perform access permission
1624  * checks on the parent table only. So we skip checking the
1625  * children's permissions and don't call
1626  * truncate_check_perms() here.
1627  */
1630 
1631  rels = lappend(rels, rel);
1632  relids = lappend_oid(relids, childrelid);
1633  /* Log this relation only if needed for logical decoding */
1634  if (RelationIsLogicallyLogged(rel))
1635  relids_logged = lappend_oid(relids_logged, childrelid);
1636  }
1637  }
1638  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1639  ereport(ERROR,
1640  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1641  errmsg("cannot truncate only a partitioned table"),
1642  errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1643  }
1644 
1645  ExecuteTruncateGuts(rels, relids, relids_logged,
1646  stmt->behavior, stmt->restart_seqs);
1647 
1648  /* And close the rels */
1649  foreach(cell, rels)
1650  {
1651  Relation rel = (Relation) lfirst(cell);
1652 
1653  table_close(rel, NoLock);
1654  }
1655 }
#define NIL
Definition: pg_list.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int errhint(const char *fmt,...)
Definition: elog.c:1071
int LOCKMODE
Definition: lockdefs.h:26
static void RangeVarCallbackForTruncate(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:15497
int errcode(int sqlerrcode)
Definition: elog.c:610
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:635
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
DropBehavior behavior
Definition: parsenodes.h:2670
struct RelationData * Relation
Definition: relcache.h:27
#define ERROR
Definition: elog.h:43
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs)
Definition: tablecmds.c:1671
List * relations
Definition: parsenodes.h:2668
#define NoLock
Definition: lockdefs.h:34
bool restart_seqs
Definition: parsenodes.h:2669
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:144
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2009
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:674
#define lfirst(lc)
Definition: pg_list.h:190
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:593
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:1963
#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:824
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:456
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ ExecuteTruncateGuts()

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

Definition at line 1671 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_num_result_relations, EState::es_result_relation_info, EState::es_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().

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

◆ find_composite_type_dependencies()

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

Definition at line 5720 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().

5722 {
5723  Relation depRel;
5724  ScanKeyData key[2];
5725  SysScanDesc depScan;
5726  HeapTuple depTup;
5727 
5728  /* since this function recurses, it could be driven to stack overflow */
5730 
5731  /*
5732  * We scan pg_depend to find those things that depend on the given type.
5733  * (We assume we can ignore refobjsubid for a type.)
5734  */
5735  depRel = table_open(DependRelationId, AccessShareLock);
5736 
5737  ScanKeyInit(&key[0],
5738  Anum_pg_depend_refclassid,
5739  BTEqualStrategyNumber, F_OIDEQ,
5740  ObjectIdGetDatum(TypeRelationId));
5741  ScanKeyInit(&key[1],
5742  Anum_pg_depend_refobjid,
5743  BTEqualStrategyNumber, F_OIDEQ,
5744  ObjectIdGetDatum(typeOid));
5745 
5746  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
5747  NULL, 2, key);
5748 
5749  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
5750  {
5751  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
5752  Relation rel;
5753  Form_pg_attribute att;
5754 
5755  /* Check for directly dependent types */
5756  if (pg_depend->classid == TypeRelationId)
5757  {
5758  /*
5759  * This must be an array, domain, or range containing the given
5760  * type, so recursively check for uses of this type. Note that
5761  * any error message will mention the original type not the
5762  * container; this is intentional.
5763  */
5764  find_composite_type_dependencies(pg_depend->objid,
5765  origRelation, origTypeName);
5766  continue;
5767  }
5768 
5769  /* Else, ignore dependees that aren't user columns of relations */
5770  /* (we assume system columns are never of interesting types) */
5771  if (pg_depend->classid != RelationRelationId ||
5772  pg_depend->objsubid <= 0)
5773  continue;
5774 
5775  rel = relation_open(pg_depend->objid, AccessShareLock);
5776  att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
5777 
5778  if (rel->rd_rel->relkind == RELKIND_RELATION ||
5779  rel->rd_rel->relkind == RELKIND_MATVIEW ||
5780  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5781  {
5782  if (origTypeName)
5783  ereport(ERROR,
5784  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5785  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5786  origTypeName,
5788  NameStr(att->attname))));
5789  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
5790  ereport(ERROR,
5791  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5792  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5793  RelationGetRelationName(origRelation),
5795  NameStr(att->attname))));
5796  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
5797  ereport(ERROR,
5798  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5799  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
5800  RelationGetRelationName(origRelation),
5802  NameStr(att->attname))));
5803  else
5804  ereport(ERROR,
5805  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5806  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
5807  RelationGetRelationName(origRelation),
5809  NameStr(att->attname))));
5810  }
5811  else if (OidIsValid(rel->rd_rel->reltype))
5812  {
5813  /*
5814  * A view or composite type itself isn't a problem, but we must
5815  * recursively check for indirect dependencies via its rowtype.
5816  */
5818  origRelation, origTypeName);
5819  }
5820 
5822  }
5823 
5824  systable_endscan(depScan);
5825 
5827 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define DependReferenceIndexId
Definition: indexing.h:151
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:5720
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:610
Form_pg_class rd_rel
Definition: rel.h:109
#define OidIsValid(objectId)
Definition: c.h:644
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
void check_stack_depth(void)
Definition: postgres.c:3312
#define RelationGetRelationName(relation)
Definition: rel.h:490
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:71
TupleDesc rd_att
Definition: rel.h:110
#define ereport(elevel,...)
Definition: elog.h:144
#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:824
#define NameStr(name)
Definition: c.h:615
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 16008 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().

16010 {
16011  List *existConstraint = NIL;
16012  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
16013  int i;
16014 
16015  if (constr && constr->has_not_null)
16016  {
16017  int natts = scanrel->rd_att->natts;
16018 
16019  for (i = 1; i <= natts; i++)
16020  {
16021  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
16022 
16023  if (att->attnotnull && !att->attisdropped)
16024  {
16025  NullTest *ntest = makeNode(NullTest);
16026 
16027  ntest->arg = (Expr *) makeVar(1,
16028  i,
16029  att->atttypid,
16030  att->atttypmod,
16031  att->attcollation,
16032  0);
16033  ntest->nulltesttype = IS_NOT_NULL;
16034 
16035  /*
16036  * argisrow=false is correct even for a composite column,
16037  * because attnotnull does not represent a SQL-spec IS NOT
16038  * NULL test in such a case, just IS DISTINCT FROM NULL.
16039  */
16040  ntest->argisrow = false;
16041  ntest->location = -1;
16042  existConstraint = lappend(existConstraint, ntest);
16043  }
16044  }
16045  }
16046 
16047  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
16048 }
#define NIL
Definition: pg_list.h:65
#define RelationGetDescr(relation)
Definition: rel.h:482
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Expr * arg
Definition: primnodes.h:1219
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:110
NullTestType nulltesttype
Definition: primnodes.h:1220
#define makeNode(_type_)
Definition: nodes.h:577
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:16061
int location
Definition: primnodes.h:1222
int i
bool argisrow
Definition: primnodes.h:1221
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 15298 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().

15299 {
15300  ListCell *l;
15301  List *oids_to_truncate = NIL;
15302  List *oids_to_drop = NIL;
15303 
15304  foreach(l, on_commits)
15305  {
15306  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
15307 
15308  /* Ignore entry if already dropped in this xact */
15310  continue;
15311 
15312  switch (oc->oncommit)
15313  {
15314  case ONCOMMIT_NOOP:
15316  /* Do nothing (there shouldn't be such entries, actually) */
15317  break;
15318  case ONCOMMIT_DELETE_ROWS:
15319 
15320  /*
15321  * If this transaction hasn't accessed any temporary
15322  * relations, we can skip truncating ON COMMIT DELETE ROWS
15323  * tables, as they must still be empty.
15324  */
15326  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
15327  break;
15328  case ONCOMMIT_DROP:
15329  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
15330  break;
15331  }
15332  }
15333 
15334  /*
15335  * Truncate relations before dropping so that all dependencies between
15336  * relations are removed after they are worked on. Doing it like this
15337  * might be a waste as it is possible that a relation being truncated will
15338  * be dropped anyway due to its parent being dropped, but this makes the
15339  * code more robust because of not having to re-check that the relation
15340  * exists at truncation time.
15341  */
15342  if (oids_to_truncate != NIL)
15343  heap_truncate(oids_to_truncate);
15344 
15345  if (oids_to_drop != NIL)
15346  {
15347  ObjectAddresses *targetObjects = new_object_addresses();
15348  ListCell *l;
15349 
15350  foreach(l, oids_to_drop)
15351  {
15352  ObjectAddress object;
15353 
15354  object.classId = RelationRelationId;
15355  object.objectId = lfirst_oid(l);
15356  object.objectSubId = 0;
15357 
15358  Assert(!object_address_present(&object, targetObjects));
15359 
15360  add_exact_object_address(&object, targetObjects);
15361  }
15362 
15363  /*
15364  * Since this is an automatic drop, rather than one directly initiated
15365  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
15366  */
15367  performMultipleDeletions(targetObjects, DROP_CASCADE,
15369 
15370 #ifdef USE_ASSERT_CHECKING
15371 
15372  /*
15373  * Note that table deletion will call remove_on_commit_action, so the
15374  * entry should get marked as deleted.
15375  */
15376  foreach(l, on_commits)
15377  {
15378  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
15379 
15380  if (oc->oncommit != ONCOMMIT_DROP)
15381  continue;
15382 
15384  }
15385 #endif
15386  }
15387 }
#define NIL
Definition: pg_list.h:65
OnCommitAction oncommit
Definition: tablecmds.c:109
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2533
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2473
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2418
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
static List * on_commits
Definition: tablecmds.c:122
int MyXactFlags
Definition: xact.c:119
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:97
SubTransactionId deleting_subid
Definition: tablecmds.c:119
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
#define PERFORM_DELETION_QUIETLY
Definition: dependency.h:136
void heap_truncate(List *relids)
Definition: heap.c:3218
#define InvalidSubTransactionId
Definition: c.h:519
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:373
Definition: pg_list.h:50
#define lfirst_oid(lc)
Definition: pg_list.h:192
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:134

◆ RangeVarCallbackOwnsRelation()

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

Definition at line 15521 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().

15523 {
15524  HeapTuple tuple;
15525 
15526  /* Nothing to do if the relation was not found. */
15527  if (!OidIsValid(relId))
15528  return;
15529 
15530  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
15531  if (!HeapTupleIsValid(tuple)) /* should not happen */
15532  elog(ERROR, "cache lookup failed for relation %u", relId);
15533 
15534  if (!pg_class_ownercheck(relId, GetUserId()))
15536  relation->relname);
15537 
15538  if (!allowSystemTableMods &&
15539  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
15540  ereport(ERROR,
15541  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
15542  errmsg("permission denied: \"%s\" is a system catalog",
15543  relation->relname)));
15544 
15545  ReleaseSysCache(tuple);
15546 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Oid GetUserId(void)
Definition: miscinit.c:448
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1866
int errcode(int sqlerrcode)
Definition: elog.c:610
#define OidIsValid(objectId)
Definition: c.h:644
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:80
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3327
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
bool allowSystemTableMods
Definition: globals.c:120
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4720
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
ObjectType get_relkind_objtype(char relkind)

◆ RangeVarCallbackOwnsTable()

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

Definition at line 15465 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().

15467 {
15468  char relkind;
15469 
15470  /* Nothing to do if the relation was not found. */
15471  if (!OidIsValid(relId))
15472  return;
15473 
15474  /*
15475  * If the relation does exist, check whether it's an index. But note that
15476  * the relation might have been dropped between the time we did the name
15477  * lookup and now. In that case, there's nothing to do.
15478  */
15479  relkind = get_rel_relkind(relId);
15480  if (!relkind)
15481  return;
15482  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
15483  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
15484  ereport(ERROR,
15485  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15486  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
15487 
15488  /* Check permissions */
15489  if (!pg_class_ownercheck(relId, GetUserId()))
15491 }
Oid GetUserId(void)
Definition: miscinit.c:448
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1866
int errcode(int sqlerrcode)
Definition: elog.c:610
#define OidIsValid(objectId)
Definition: c.h:644
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3327
#define ERROR
Definition: elog.h:43
#define ereport(elevel,...)
Definition: elog.h:144
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4720
int errmsg(const char *fmt,...)
Definition: elog.c:824
ObjectType get_relkind_objtype(char relkind)

◆ register_on_commit_action()

void register_on_commit_action ( Oid  relid,
OnCommitAction  action 
)

Definition at line 15239 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().

15240 {
15241  OnCommitItem *oc;
15242  MemoryContext oldcxt;
15243 
15244  /*
15245  * We needn't bother registering the relation unless there is an ON COMMIT
15246  * action we need to take.
15247  */
15249  return;
15250 
15252 
15253  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
15254  oc->relid = relid;
15255  oc->oncommit = action;
15258 
15259  /*
15260  * We use lcons() here so that ON COMMIT actions are processed in reverse
15261  * order of registration. That might not be essential but it seems
15262  * reasonable.
15263  */
15264  on_commits = lcons(oc, on_commits);
15265 
15266  MemoryContextSwitchTo(oldcxt);
15267 }
OnCommitAction oncommit
Definition: tablecmds.c:109
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
SubTransactionId creating_subid
Definition: tablecmds.c:118
static List * on_commits
Definition: tablecmds.c:122
SubTransactionId deleting_subid
Definition: tablecmds.c:119
List * lcons(void *datum, List *list)
Definition: list.c:453
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:708
#define InvalidSubTransactionId
Definition: c.h:519
void * palloc(Size size)
Definition: mcxt.c:949
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ remove_on_commit_action()

void remove_on_commit_action ( Oid  relid)

Definition at line 15275 of file tablecmds.c.

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

Referenced by heap_drop_with_catalog().

15276 {
15277  ListCell *l;
15278 
15279  foreach(l, on_commits)
15280  {
15281  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
15282 
15283  if (oc->relid == relid)
15284  {
15286  break;
15287  }
15288  }
15289 }
static List * on_commits
Definition: tablecmds.c:122
SubTransactionId deleting_subid
Definition: tablecmds.c:119
#define lfirst(lc)
Definition: pg_list.h:190
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:708

◆ RemoveRelations()

void RemoveRelations ( DropStmt drop)

Definition at line 1256 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(), 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, DropStmt::removeType, RVR_MISSING_OK, and ShareUpdateExclusiveLock.

Referenced by ExecDropStmt().

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

◆ renameatt()

ObjectAddress renameatt ( RenameStmt stmt)

Definition at line 3196 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().

3197 {
3198  Oid relid;
3200  ObjectAddress address;
3201 
3202  /* lock level taken here should match renameatt_internal */
3204  stmt->missing_ok ? RVR_MISSING_OK : 0,
3206  NULL);
3207 
3208  if (!OidIsValid(relid))
3209  {
3210  ereport(NOTICE,
3211  (errmsg("relation \"%s\" does not exist, skipping",
3212  stmt->relation->relname)));
3213  return InvalidObjectAddress;
3214  }
3215 
3216  attnum =
3217  renameatt_internal(relid,
3218  stmt->subname, /* old att name */
3219  stmt->newname, /* new att name */
3220  stmt->relation->inh, /* recursive? */
3221  false, /* recursing? */
3222  0, /* expected inhcount */
3223  stmt->behavior);
3224 
3225  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3226 
3227  return address;
3228 }
char * subname
Definition: parsenodes.h:2921
char * newname
Definition: parsenodes.h:2923
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2925
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:2919
int16 attnum
Definition: pg_attribute.h:79
#define ereport(elevel,...)
Definition: elog.h:144
#define NOTICE
Definition: elog.h:37
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3176
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:3031
#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:824
DropBehavior behavior
Definition: parsenodes.h:2924
int16 AttrNumber
Definition: attnum.h:21

◆ RenameConstraint()

ObjectAddress RenameConstraint ( RenameStmt stmt)

Definition at line 3340 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().

3341 {
3342  Oid relid = InvalidOid;
3343  Oid typid = InvalidOid;
3344 
3345  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3346  {
3347  Relation rel;
3348  HeapTuple tup;
3349 
3351  rel = table_open(TypeRelationId, RowExclusiveLock);
3352  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3353  if (!HeapTupleIsValid(tup))
3354  elog(ERROR, "cache lookup failed for type %u", typid);
3355  checkDomainOwner(tup);
3356  ReleaseSysCache(tup);
3357  table_close(rel, NoLock);
3358  }
3359  else
3360  {
3361  /* lock level taken here should match rename_constraint_internal */
3363  stmt->missing_ok ? RVR_MISSING_OK : 0,
3365  NULL);
3366  if (!OidIsValid(relid))
3367  {
3368  ereport(NOTICE,
3369  (errmsg("relation \"%s\" does not exist, skipping",
3370  stmt->relation->relname)));
3371  return InvalidObjectAddress;
3372  }
3373  }
3374 
3375  return
3376  rename_constraint_internal(relid, typid,
3377  stmt->subname,
3378  stmt->newname,
3379  (stmt->relation &&
3380  stmt->relation->inh), /* recursive? */
3381  false, /* recursing? */
3382  0 /* expected inhcount */ );
3383 
3384 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
char * subname
Definition: parsenodes.h:2921
ObjectType renameType
Definition: parsenodes.h:2917
#define castNode(_type_, nodeptr)
Definition: nodes.h:598
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:3234
char * newname
Definition: parsenodes.h:2923
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2925
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Node * object
Definition: parsenodes.h:2920
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:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
RangeVar * relation
Definition: parsenodes.h:2919
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#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:3176
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:2978
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:454
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 3391 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().

3392 {
3393  bool is_index = stmt->renameType == OBJECT_INDEX;
3394  Oid relid;
3395  ObjectAddress address;
3396 
3397  /*
3398  * Grab an exclusive lock on the target table, index, sequence, view,
3399  * materialized view, or foreign table, which we will NOT release until
3400  * end of transaction.
3401  *
3402  * Lock level used here should match RenameRelationInternal, to avoid lock
3403  * escalation.
3404  */
3405  relid = RangeVarGetRelidExtended(stmt->relation,
3407  stmt->missing_ok ? RVR_MISSING_OK : 0,
3409  (void *) stmt);
3410 
3411  if (!OidIsValid(relid))
3412  {
3413  ereport(NOTICE,
3414  (errmsg("relation \"%s\" does not exist, skipping",
3415  stmt->relation->relname)));
3416  return InvalidObjectAddress;
3417  }
3418 
3419  /* Do the work */
3420  RenameRelationInternal(relid, stmt->newname, false, is_index);
3421 
3422  ObjectAddressSet(address, RelationRelationId, relid);
3423 
3424  return address;
3425 }
ObjectType renameType
Definition: parsenodes.h:2917
char * newname
Definition: parsenodes.h:2923
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2925
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:15553
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
RangeVar * relation
Definition: parsenodes.h:2919
#define ereport(elevel,...)
Definition: elog.h:144
#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:824
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3431

◆ RenameRelationInternal()

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

Definition at line 3431 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().

3432 {
3433  Relation targetrelation;
3434  Relation relrelation; /* for RELATION relation */
3435  HeapTuple reltup;
3436  Form_pg_class relform;
3437  Oid namespaceId;
3438 
3439  /*
3440  * Grab a lock on the target relation, which we will NOT release until end
3441  * of transaction. We need at least a self-exclusive lock so that
3442  * concurrent DDL doesn't overwrite the rename if they start updating
3443  * while still seeing the old version. The lock also guards against
3444  * triggering relcache reloads in concurrent sessions, which might not
3445  * handle this information changing under them. For indexes, we can use a
3446  * reduced lock level because RelationReloadIndexInfo() handles indexes
3447  * specially.
3448  */
3449  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
3450  namespaceId = RelationGetNamespace(targetrelation);
3451 
3452  /*
3453  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3454  */
3455  relrelation = table_open(RelationRelationId, RowExclusiveLock);
3456 
3457  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3458  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3459  elog(ERROR, "cache lookup failed for relation %u", myrelid);
3460  relform = (Form_pg_class) GETSTRUCT(reltup);
3461 
3462  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3463  ereport(ERROR,
3464  (errcode(ERRCODE_DUPLICATE_TABLE),
3465  errmsg("relation \"%s\" already exists",
3466  newrelname)));
3467 
3468  /*
3469  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
3470  * because it's a copy...)
3471  */
3472  namestrcpy(&(relform->relname), newrelname);
3473 
3474  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3475 
3476  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
3477  InvalidOid, is_internal);
3478 
3479  heap_freetuple(reltup);
3480  table_close(relrelation, RowExclusiveLock);
3481 
3482  /*
3483  * Also rename the associated type, if any.
3484  */
3485  if (OidIsValid(targetrelation->rd_rel->reltype))
3486  RenameTypeInternal(targetrelation->rd_rel->reltype,
3487  newrelname, namespaceId);
3488 
3489  /*
3490  * Also rename the associated constraint, if any.
3491  */
3492  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3493  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3494  {
3495  Oid constraintId = get_index_constraint(myrelid);
3496 
3497  if (OidIsValid(constraintId))
3498  RenameConstraintById(constraintId, newrelname);
3499  }
3500 
3501  /*
3502  * Close rel, but keep lock!
3503  */
3504  relation_close(targetrelation, NoLock);
3505 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
int errcode(int sqlerrcode)
Definition: elog.c:610
Form_pg_class rd_rel
Definition: rel.h:109
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:250
#define OidIsValid(objectId)
Definition: c.h:644
#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:43
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:1748
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:965
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:735
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#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:224
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetNamespace(relation)
Definition: rel.h:497

◆ SetRelationHasSubclass()

void SetRelationHasSubclass ( Oid  relationId,
bool  relhassubclass 
)

Definition at line 2949 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().

2950 {
2951  Relation relationRelation;
2952  HeapTuple tuple;
2953  Form_pg_class classtuple;
2954 
2955  /*
2956  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
2957  */
2958  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
2959  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
2960  if (!HeapTupleIsValid(tuple))
2961  elog(ERROR, "cache lookup failed for relation %u", relationId);
2962  classtuple = (Form_pg_class) GETSTRUCT(tuple);
2963 
2964  if (classtuple->relhassubclass != relhassubclass)
2965  {
2966  classtuple->relhassubclass = relhassubclass;
2967  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
2968  }
2969  else
2970  {
2971  /* no need to change tuple, but force relcache rebuild anyway */
2973  }
2974 
2975  heap_freetuple(tuple);
2976  table_close(relationRelation, RowExclusiveLock);
2977 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#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:43
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:224
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
#define elog(elevel,...)
Definition: elog.h:214
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1306
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39