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

14849 {
14850  HeapTuple classTup;
14851  Form_pg_class classForm;
14852  ObjectAddress thisobj;
14853  bool already_done = false;
14854 
14855  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
14856  if (!HeapTupleIsValid(classTup))
14857  elog(ERROR, "cache lookup failed for relation %u", relOid);
14858  classForm = (Form_pg_class) GETSTRUCT(classTup);
14859 
14860  Assert(classForm->relnamespace == oldNspOid);
14861 
14862  thisobj.classId = RelationRelationId;
14863  thisobj.objectId = relOid;
14864  thisobj.objectSubId = 0;
14865 
14866  /*
14867  * If the object has already been moved, don't move it again. If it's
14868  * already in the right place, don't move it, but still fire the object
14869  * access hook.
14870  */
14871  already_done = object_address_present(&thisobj, objsMoved);
14872  if (!already_done && oldNspOid != newNspOid)
14873  {
14874  /* check for duplicate name (more friendly than unique-index failure) */
14875  if (get_relname_relid(NameStr(classForm->relname),
14876  newNspOid) != InvalidOid)
14877  ereport(ERROR,
14878  (errcode(ERRCODE_DUPLICATE_TABLE),
14879  errmsg("relation \"%s\" already exists in schema \"%s\"",
14880  NameStr(classForm->relname),
14881  get_namespace_name(newNspOid))));
14882 
14883  /* classTup is a copy, so OK to scribble on */
14884  classForm->relnamespace = newNspOid;
14885 
14886  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
14887 
14888  /* Update dependency on schema if caller said so */
14889  if (hasDependEntry &&
14890  changeDependencyFor(RelationRelationId,
14891  relOid,
14892  NamespaceRelationId,
14893  oldNspOid,
14894  newNspOid) != 1)
14895  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
14896  NameStr(classForm->relname));
14897  }
14898  if (!already_done)
14899  {
14900  add_exact_object_address(&thisobj, objsMoved);
14901 
14902  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
14903  }
14904 
14905  heap_freetuple(classTup);
14906 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2529
int errcode(int sqlerrcode)
Definition: elog.c:608
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2469
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:1687
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define InvalidOid
Definition: postgres_ext.h:36
#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:822
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:297
#define elog(elevel,...)
Definition: elog.h:228
#define NameStr(name)
Definition: c.h:615

◆ AlterTable()

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

Definition at line 3562 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3564 {
3565  Relation rel;
3566 
3567  /* Caller is required to provide an adequate lock. */
3568  rel = relation_open(context->relid, NoLock);
3569 
3570  CheckTableNotInUse(rel, "ALTER TABLE");
3571 
3572  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
3573 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:3897
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:3478
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1774

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

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

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

◆ AlterTableInternal()

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

Definition at line 3591 of file tablecmds.c.

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

3592 {
3593  Relation rel;
3594  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
3595 
3596  rel = relation_open(relid, lockmode);
3597 
3599 
3600  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
3601 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:3897
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:3636
void EventTriggerAlterTableRelid(Oid objectId)

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3506 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3507 {
3508  return RangeVarGetRelidExtended(stmt->relation, lockmode,
3509  stmt->missing_ok ? RVR_MISSING_OK : 0,
3511  (void *) stmt);
3512 }
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:15359
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:228
RangeVar * relation
Definition: parsenodes.h:1774

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

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

13041 {
13042  List *relations = NIL;
13043  ListCell *l;
13044  ScanKeyData key[1];
13045  Relation rel;
13046  TableScanDesc scan;
13047  HeapTuple tuple;
13048  Oid orig_tablespaceoid;
13049  Oid new_tablespaceoid;
13050  List *role_oids = roleSpecsToIds(stmt->roles);
13051 
13052  /* Ensure we were not asked to move something we can't */
13053  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
13054  stmt->objtype != OBJECT_MATVIEW)
13055  ereport(ERROR,
13056  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13057  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
13058 
13059  /* Get the orig and new tablespace OIDs */
13060  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
13061  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
13062 
13063  /* Can't move shared relations in to or out of pg_global */
13064  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
13065  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
13066  new_tablespaceoid == GLOBALTABLESPACE_OID)
13067  ereport(ERROR,
13068  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13069  errmsg("cannot move relations in to or out of pg_global tablespace")));
13070 
13071  /*
13072  * Must have CREATE rights on the new tablespace, unless it is the
13073  * database default tablespace (which all users implicitly have CREATE
13074  * rights on).
13075  */
13076  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
13077  {
13078  AclResult aclresult;
13079 
13080  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
13081  ACL_CREATE);
13082  if (aclresult != ACLCHECK_OK)
13083  aclcheck_error(aclresult, OBJECT_TABLESPACE,
13084  get_tablespace_name(new_tablespaceoid));
13085  }
13086 
13087  /*
13088  * Now that the checks are done, check if we should set either to
13089  * InvalidOid because it is our database's default tablespace.
13090  */
13091  if (orig_tablespaceoid == MyDatabaseTableSpace)
13092  orig_tablespaceoid = InvalidOid;
13093 
13094  if (new_tablespaceoid == MyDatabaseTableSpace)
13095  new_tablespaceoid = InvalidOid;
13096 
13097  /* no-op */
13098  if (orig_tablespaceoid == new_tablespaceoid)
13099  return new_tablespaceoid;
13100 
13101  /*
13102  * Walk the list of objects in the tablespace and move them. This will
13103  * only find objects in our database, of course.
13104  */
13105  ScanKeyInit(&key[0],
13106  Anum_pg_class_reltablespace,
13107  BTEqualStrategyNumber, F_OIDEQ,
13108  ObjectIdGetDatum(orig_tablespaceoid));
13109 
13110  rel = table_open(RelationRelationId, AccessShareLock);
13111  scan = table_beginscan_catalog(rel, 1, key);
13112  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
13113  {
13114  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
13115  Oid relOid = relForm->oid;
13116 
13117  /*
13118  * Do not move objects in pg_catalog as part of this, if an admin
13119  * really wishes to do so, they can issue the individual ALTER
13120  * commands directly.
13121  *
13122  * Also, explicitly avoid any shared tables, temp tables, or TOAST
13123  * (TOAST will be moved with the main table).
13124  */
13125  if (IsCatalogNamespace(relForm->relnamespace) ||
13126  relForm->relisshared ||
13127  isAnyTempNamespace(relForm->relnamespace) ||
13128  IsToastNamespace(relForm->relnamespace))
13129  continue;
13130 
13131  /* Only move the object type requested */
13132  if ((stmt->objtype == OBJECT_TABLE &&
13133  relForm->relkind != RELKIND_RELATION &&
13134  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
13135  (stmt->objtype == OBJECT_INDEX &&
13136  relForm->relkind != RELKIND_INDEX &&
13137  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
13138  (stmt->objtype == OBJECT_MATVIEW &&
13139  relForm->relkind != RELKIND_MATVIEW))
13140  continue;
13141 
13142  /* Check if we are only moving objects owned by certain roles */
13143  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
13144  continue;
13145 
13146  /*
13147  * Handle permissions-checking here since we are locking the tables
13148  * and also to avoid doing a bunch of work only to fail part-way. Note
13149  * that permissions will also be checked by AlterTableInternal().
13150  *
13151  * Caller must be considered an owner on the table to move it.
13152  */
13153  if (!pg_class_ownercheck(relOid, GetUserId()))
13155  NameStr(relForm->relname));
13156 
13157  if (stmt->nowait &&
13159  ereport(ERROR,
13160  (errcode(ERRCODE_OBJECT_IN_USE),
13161  errmsg("aborting because lock on relation \"%s.%s\" is not available",
13162  get_namespace_name(relForm->relnamespace),
13163  NameStr(relForm->relname))));
13164  else
13166 
13167  /* Add to our list of objects to move */
13168  relations = lappend_oid(relations, relOid);
13169  }
13170 
13171  table_endscan(scan);
13173 
13174  if (relations == NIL)
13175  ereport(NOTICE,
13176  (errcode(ERRCODE_NO_DATA_FOUND),
13177  errmsg("no matching relations in tablespace \"%s\" found",
13178  orig_tablespaceoid == InvalidOid ? "(database default)" :
13179  get_tablespace_name(orig_tablespaceoid))));
13180 
13181  /* Everything is locked, loop through and move all of the relations. */
13182  foreach(l, relations)
13183  {
13184  List *cmds = NIL;
13186 
13187  cmd->subtype = AT_SetTableSpace;
13188  cmd->name = stmt->new_tablespacename;
13189 
13190  cmds = lappend(cmds, cmd);
13191 
13193  /* OID is set by AlterTableInternal */
13194  AlterTableInternal(lfirst_oid(l), cmds, false);
13196  }
13197 
13198  return new_tablespaceoid;
13199 }
#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:4703
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:378
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:525
int errcode(int sqlerrcode)
Definition: elog.c:608
AlterTableType subtype
Definition: parsenodes.h:1860
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:358
#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:3352
#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:3094
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1291
#define ereport(elevel, rest)
Definition: elog.h:141
List * lappend(List *list, void *datum)
Definition: list.c:322
AclResult
Definition: acl.h:177
#define InvalidOid
Definition: postgres_ext.h:36
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:573
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1423
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:675
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4753
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:177
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:863
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:3591
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:822
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:3187
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 14736 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().

14737 {
14738  Relation rel;
14739  Oid relid;
14740  Oid oldNspOid;
14741  Oid nspOid;
14742  RangeVar *newrv;
14743  ObjectAddresses *objsMoved;
14744  ObjectAddress myself;
14745 
14747  stmt->missing_ok ? RVR_MISSING_OK : 0,
14749  (void *) stmt);
14750 
14751  if (!OidIsValid(relid))
14752  {
14753  ereport(NOTICE,
14754  (errmsg("relation \"%s\" does not exist, skipping",
14755  stmt->relation->relname)));
14756  return InvalidObjectAddress;
14757  }
14758 
14759  rel = relation_open(relid, NoLock);
14760 
14761  oldNspOid = RelationGetNamespace(rel);
14762 
14763  /* If it's an owned sequence, disallow moving it by itself. */
14764  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
14765  {
14766  Oid tableId;
14767  int32 colId;
14768 
14769  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
14770  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
14771  ereport(ERROR,
14772  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14773  errmsg("cannot move an owned sequence into another schema"),
14774  errdetail("Sequence \"%s\" is linked to table \"%s\".",
14776  get_rel_name(tableId))));
14777  }
14778 
14779  /* Get and lock schema OID and check its permissions. */
14780  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
14781  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
14782 
14783  /* common checks on switching namespaces */
14784  CheckSetNamespace(oldNspOid, nspOid);
14785 
14786  objsMoved = new_object_addresses();
14787  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
14788  free_object_addresses(objsMoved);
14789 
14790  ObjectAddressSet(myself, RelationRelationId, relid);
14791 
14792  if (oldschema)
14793  *oldschema = oldNspOid;
14794 
14795  /* close rel, but keep lock until commit */
14796  relation_close(rel, NoLock);
14797 
14798  return myself;
14799 }
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:663
int errcode(int sqlerrcode)
Definition: elog.c:608
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2414
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2709
Form_pg_class rd_rel
Definition: rel.h:84
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:14807
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:15359
int errdetail(const char *fmt,...)
Definition: elog.c:955
#define RelationGetRelationName(relation)
Definition: rel.h:462
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:228
#define ereport(elevel, rest)
Definition: elog.h:141
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2959
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:526
#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:822
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:420
#define RelationGetNamespace(relation)
Definition: rel.h:469

◆ AlterTableNamespaceInternal()

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

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

14809 {
14810  Relation classRel;
14811 
14812  Assert(objsMoved != NULL);
14813 
14814  /* OK, modify the pg_class row and pg_depend entry */
14815  classRel = table_open(RelationRelationId, RowExclusiveLock);
14816 
14817  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
14818  nspOid, true, objsMoved);
14819 
14820  /* Fix the table's row type too */
14821  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
14822  nspOid, false, false, objsMoved);
14823 
14824  /* Fix other dependent stuff */
14825  if (rel->rd_rel->relkind == RELKIND_RELATION ||
14826  rel->rd_rel->relkind == RELKIND_MATVIEW ||
14827  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14828  {
14829  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
14830  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
14831  objsMoved, AccessExclusiveLock);
14832  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
14833  false, objsMoved);
14834  }
14835 
14836  table_close(classRel, RowExclusiveLock);
14837 }
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:3579
Form_pg_class rd_rel
Definition: rel.h:84
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:14915
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:14960
#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:14845
#define AccessExclusiveLock
Definition: lockdefs.h:45
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:428

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 15236 of file tablecmds.c.

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

15238 {
15239  ListCell *cur_item;
15240 
15241  foreach(cur_item, on_commits)
15242  {
15243  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
15244 
15245  if (!isCommit && oc->creating_subid == mySubid)
15246  {
15247  /* cur_item must be removed */
15249  pfree(oc);
15250  }
15251  else
15252  {
15253  /* cur_item must be preserved */
15254  if (oc->creating_subid == mySubid)
15255  oc->creating_subid = parentSubid;
15256  if (oc->deleting_subid == mySubid)
15257  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
15258  }
15259  }
15260 }
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 15204 of file tablecmds.c.

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

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

15205 {
15206  ListCell *cur_item;
15207 
15208  foreach(cur_item, on_commits)
15209  {
15210  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
15211 
15212  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
15214  {
15215  /* cur_item must be removed */
15217  pfree(oc);
15218  }
15219  else
15220  {
15221  /* cur_item must be preserved */
15224  }
15225  }
15226 }
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 12188 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().

12189 {
12190  Relation target_rel;
12191  Relation class_rel;
12192  HeapTuple tuple;
12193  Form_pg_class tuple_class;
12194 
12195  /*
12196  * Get exclusive lock till end of transaction on the target table. Use
12197  * relation_open so that we can work on indexes and sequences.
12198  */
12199  target_rel = relation_open(relationOid, lockmode);
12200 
12201  /* Get its pg_class tuple, too */
12202  class_rel = table_open(RelationRelationId, RowExclusiveLock);
12203 
12204  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
12205  if (!HeapTupleIsValid(tuple))
12206  elog(ERROR, "cache lookup failed for relation %u", relationOid);
12207  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
12208 
12209  /* Can we change the ownership of this tuple? */
12210  switch (tuple_class->relkind)
12211  {
12212  case RELKIND_RELATION:
12213  case RELKIND_VIEW:
12214  case RELKIND_MATVIEW:
12215  case RELKIND_FOREIGN_TABLE:
12216  case RELKIND_PARTITIONED_TABLE:
12217  /* ok to change owner */
12218  break;
12219  case RELKIND_INDEX:
12220  if (!recursing)
12221  {
12222  /*
12223  * Because ALTER INDEX OWNER used to be allowed, and in fact
12224  * is generated by old versions of pg_dump, we give a warning
12225  * and do nothing rather than erroring out. Also, to avoid
12226  * unnecessary chatter while restoring those old dumps, say
12227  * nothing at all if the command would be a no-op anyway.
12228  */
12229  if (tuple_class->relowner != newOwnerId)
12230  ereport(WARNING,
12231  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12232  errmsg("cannot change owner of index \"%s\"",
12233  NameStr(tuple_class->relname)),
12234  errhint("Change the ownership of the index's table, instead.")));
12235  /* quick hack to exit via the no-op path */
12236  newOwnerId = tuple_class->relowner;
12237  }
12238  break;
12239  case RELKIND_PARTITIONED_INDEX:
12240  if (recursing)
12241  break;
12242  ereport(ERROR,
12243  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12244  errmsg("cannot change owner of index \"%s\"",
12245  NameStr(tuple_class->relname)),
12246  errhint("Change the ownership of the index's table, instead.")));
12247  break;
12248  case RELKIND_SEQUENCE:
12249  if (!recursing &&
12250  tuple_class->relowner != newOwnerId)
12251  {
12252  /* if it's an owned sequence, disallow changing it by itself */
12253  Oid tableId;
12254  int32 colId;
12255 
12256  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
12257  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
12258  ereport(ERROR,
12259  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12260  errmsg("cannot change owner of sequence \"%s\"",
12261  NameStr(tuple_class->relname)),
12262  errdetail("Sequence \"%s\" is linked to table \"%s\".",
12263  NameStr(tuple_class->relname),
12264  get_rel_name(tableId))));
12265  }
12266  break;
12267  case RELKIND_COMPOSITE_TYPE:
12268  if (recursing)
12269  break;
12270  ereport(ERROR,
12271  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12272  errmsg("\"%s\" is a composite type",
12273  NameStr(tuple_class->relname)),
12274  errhint("Use ALTER TYPE instead.")));
12275  break;
12276  case RELKIND_TOASTVALUE:
12277  if (recursing)
12278  break;
12279  /* FALL THRU */
12280  default:
12281  ereport(ERROR,
12282  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12283  errmsg("\"%s\" is not a table, view, sequence, or foreign table",
12284  NameStr(tuple_class->relname))));
12285  }
12286 
12287  /*
12288  * If the new owner is the same as the existing owner, consider the
12289  * command to have succeeded. This is for dump restoration purposes.
12290  */
12291  if (tuple_class->relowner != newOwnerId)
12292  {
12293  Datum repl_val[Natts_pg_class];
12294  bool repl_null[Natts_pg_class];
12295  bool repl_repl[Natts_pg_class];
12296  Acl *newAcl;
12297  Datum aclDatum;
12298  bool isNull;
12299  HeapTuple newtuple;
12300 
12301  /* skip permission checks when recursing to index or toast table */
12302  if (!recursing)
12303  {
12304  /* Superusers can always do it */
12305  if (!superuser())
12306  {
12307  Oid namespaceOid = tuple_class->relnamespace;
12308  AclResult aclresult;
12309 
12310  /* Otherwise, must be owner of the existing object */
12311  if (!pg_class_ownercheck(relationOid, GetUserId()))
12313  RelationGetRelationName(target_rel));
12314 
12315  /* Must be able to become new owner */
12316  check_is_member_of_role(GetUserId(), newOwnerId);
12317 
12318  /* New owner must have CREATE privilege on namespace */
12319  aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
12320  ACL_CREATE);
12321  if (aclresult != ACLCHECK_OK)
12322  aclcheck_error(aclresult, OBJECT_SCHEMA,
12323  get_namespace_name(namespaceOid));
12324  }
12325  }
12326 
12327  memset(repl_null, false, sizeof(repl_null));
12328  memset(repl_repl, false, sizeof(repl_repl));
12329 
12330  repl_repl[Anum_pg_class_relowner - 1] = true;
12331  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
12332 
12333  /*
12334  * Determine the modified ACL for the new owner. This is only
12335  * necessary when the ACL is non-null.
12336  */
12337  aclDatum = SysCacheGetAttr(RELOID, tuple,
12338  Anum_pg_class_relacl,
12339  &isNull);
12340  if (!isNull)
12341  {
12342  newAcl = aclnewowner(DatumGetAclP(aclDatum),
12343  tuple_class->relowner, newOwnerId);
12344  repl_repl[Anum_pg_class_relacl - 1] = true;
12345  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
12346  }
12347 
12348  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
12349 
12350  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
12351 
12352  heap_freetuple(newtuple);
12353 
12354  /*
12355  * We must similarly update any per-column ACLs to reflect the new
12356  * owner; for neatness reasons that's split out as a subroutine.
12357  */
12358  change_owner_fix_column_acls(relationOid,
12359  tuple_class->relowner,
12360  newOwnerId);
12361 
12362  /*
12363  * Update owner dependency reference, if any. A composite type has
12364  * none, because it's tracked for the pg_type entry instead of here;
12365  * indexes and TOAST tables don't have their own entries either.
12366  */
12367  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
12368  tuple_class->relkind != RELKIND_INDEX &&
12369  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
12370  tuple_class->relkind != RELKIND_TOASTVALUE)
12371  changeDependencyOnOwner(RelationRelationId, relationOid,
12372  newOwnerId);
12373 
12374  /*
12375  * Also change the ownership of the table's row type, if it has one
12376  */
12377  if (tuple_class->relkind != RELKIND_INDEX &&
12378  tuple_class->relkind != RELKIND_PARTITIONED_INDEX)
12379  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
12380 
12381  /*
12382  * If we are operating on a table or materialized view, also change
12383  * the ownership of any indexes and sequences that belong to the
12384  * relation, as well as its toast table (if it has one).
12385  */
12386  if (tuple_class->relkind == RELKIND_RELATION ||
12387  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
12388  tuple_class->relkind == RELKIND_MATVIEW ||
12389  tuple_class->relkind == RELKIND_TOASTVALUE)
12390  {
12391  List *index_oid_list;
12392  ListCell *i;
12393 
12394  /* Find all the indexes belonging to this relation */
12395  index_oid_list = RelationGetIndexList(target_rel);
12396 
12397  /* For each index, recursively change its ownership */
12398  foreach(i, index_oid_list)
12399  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
12400 
12401  list_free(index_oid_list);
12402  }
12403 
12404  /* If it has a toast table, recurse to change its ownership */
12405  if (tuple_class->reltoastrelid != InvalidOid)
12406  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
12407  true, lockmode);
12408 
12409  /* If it has dependent sequences, recurse to change them too */
12410  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
12411  }
12412 
12413  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
12414 
12415  ReleaseSysCache(tuple);
12416  table_close(class_rel, RowExclusiveLock);
12417  relation_close(target_rel, NoLock);
12418 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int errhint(const char *fmt,...)
Definition: elog.c:1069
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:663
#define RelationGetDescr(relation)
Definition: rel.h:454
Oid GetUserId(void)
Definition: miscinit.c:378
#define DatumGetAclP(X)
Definition: acl.h:120
#define PointerGetDatum(X)
Definition: postgres.h:556
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
int errcode(int sqlerrcode)
Definition: elog.c:608
bool superuser(void)
Definition: superuser.c:46
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3449
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:4691
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:3352
#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:3094
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:955
#define RelationGetRelationName(relation)
Definition: rel.h:462
void check_is_member_of_role(Oid member, Oid role)
Definition: acl.c:4946
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:12188
#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 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:4753
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:12492
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4333
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:12427
int errmsg(const char *fmt,...)
Definition: elog.c:822
void list_free(List *list)
Definition: list.c:1377
#define elog(elevel,...)
Definition: elog.h:228
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:1730
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1052
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ check_of_type()

void check_of_type ( HeapTuple  typetuple)

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

5836 {
5837  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
5838  bool typeOk = false;
5839 
5840  if (typ->typtype == TYPTYPE_COMPOSITE)
5841  {
5842  Relation typeRelation;
5843 
5844  Assert(OidIsValid(typ->typrelid));
5845  typeRelation = relation_open(typ->typrelid, AccessShareLock);
5846  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
5847 
5848  /*
5849  * Close the parent rel, but keep our AccessShareLock on it until xact
5850  * commit. That will prevent someone else from deleting or ALTERing
5851  * the type before the typed table creation/conversion commits.
5852  */
5853  relation_close(typeRelation, NoLock);
5854  }
5855  if (!typeOk)
5856  ereport(ERROR,
5857  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5858  errmsg("type %s is not a composite type",
5859  format_type_be(typ->oid))));
5860 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:608
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
Form_pg_class rd_rel
Definition: rel.h:84
#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, rest)
Definition: elog.h:141
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:250
int errmsg(const char *fmt,...)
Definition: elog.c:822

◆ CheckTableNotInUse()

void CheckTableNotInUse ( Relation  rel,
const char *  stmt 
)

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

3479 {
3480  int expected_refcnt;
3481 
3482  expected_refcnt = rel->rd_isnailed ? 2 : 1;
3483  if (rel->rd_refcnt != expected_refcnt)
3484  ereport(ERROR,
3485  (errcode(ERRCODE_OBJECT_IN_USE),
3486  /* translator: first %s is a SQL command, eg ALTER TABLE */
3487  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
3488  stmt, RelationGetRelationName(rel))));
3489 
3490  if (rel->rd_rel->relkind != RELKIND_INDEX &&
3491  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
3493  ereport(ERROR,
3494  (errcode(ERRCODE_OBJECT_IN_USE),
3495  /* translator: first %s is a SQL command, eg ALTER TABLE */
3496  errmsg("cannot %s \"%s\" because it has pending trigger events",
3497  stmt, RelationGetRelationName(rel))));
3498 }
bool rd_isnailed
Definition: rel.h:61
int errcode(int sqlerrcode)
Definition: elog.c:608
Form_pg_class rd_rel
Definition: rel.h:84
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:462
#define ereport(elevel, rest)
Definition: elog.h:141
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5640
int errmsg(const char *fmt,...)
Definition: elog.c:822
int rd_refcnt
Definition: rel.h:58
#define RelationGetRelid(relation)
Definition: rel.h:428

◆ DefineRelation()

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

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

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

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

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

◆ find_composite_type_dependencies()

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

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

5670 {
5671  Relation depRel;
5672  ScanKeyData key[2];
5673  SysScanDesc depScan;
5674  HeapTuple depTup;
5675 
5676  /* since this function recurses, it could be driven to stack overflow */
5678 
5679  /*
5680  * We scan pg_depend to find those things that depend on the given type.
5681  * (We assume we can ignore refobjsubid for a type.)
5682  */
5683  depRel = table_open(DependRelationId, AccessShareLock);
5684 
5685  ScanKeyInit(&key[0],
5686  Anum_pg_depend_refclassid,
5687  BTEqualStrategyNumber, F_OIDEQ,
5688  ObjectIdGetDatum(TypeRelationId));
5689  ScanKeyInit(&key[1],
5690  Anum_pg_depend_refobjid,
5691  BTEqualStrategyNumber, F_OIDEQ,
5692  ObjectIdGetDatum(typeOid));
5693 
5694  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
5695  NULL, 2, key);
5696 
5697  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
5698  {
5699  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
5700  Relation rel;
5701  Form_pg_attribute att;
5702 
5703  /* Check for directly dependent types */
5704  if (pg_depend->classid == TypeRelationId)
5705  {
5706  /*
5707  * This must be an array, domain, or range containing the given
5708  * type, so recursively check for uses of this type. Note that
5709  * any error message will mention the original type not the
5710  * container; this is intentional.
5711  */
5712  find_composite_type_dependencies(pg_depend->objid,
5713  origRelation, origTypeName);
5714  continue;
5715  }
5716 
5717  /* Else, ignore dependees that aren't user columns of relations */
5718  /* (we assume system columns are never of interesting types) */
5719  if (pg_depend->classid != RelationRelationId ||
5720  pg_depend->objsubid <= 0)
5721  continue;
5722 
5723  rel = relation_open(pg_depend->objid, AccessShareLock);
5724  att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
5725 
5726  if (rel->rd_rel->relkind == RELKIND_RELATION ||
5727  rel->rd_rel->relkind == RELKIND_MATVIEW ||
5728  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5729  {
5730  if (origTypeName)
5731  ereport(ERROR,
5732  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5733  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5734  origTypeName,
5736  NameStr(att->attname))));
5737  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
5738  ereport(ERROR,
5739  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5740  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5741  RelationGetRelationName(origRelation),
5743  NameStr(att->attname))));
5744  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
5745  ereport(ERROR,
5746  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5747  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
5748  RelationGetRelationName(origRelation),
5750  NameStr(att->attname))));
5751  else
5752  ereport(ERROR,
5753  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5754  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
5755  RelationGetRelationName(origRelation),
5757  NameStr(att->attname))));
5758  }
5759  else if (OidIsValid(rel->rd_rel->reltype))
5760  {
5761  /*
5762  * A view or composite type itself isn't a problem, but we must
5763  * recursively check for indirect dependencies via its rowtype.
5764  */
5766  origRelation, origTypeName);
5767  }
5768 
5770  }
5771 
5772  systable_endscan(depScan);
5773 
5775 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#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:5668
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:608
Form_pg_class rd_rel
Definition: rel.h:84
#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:352
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#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:3288
#define RelationGetRelationName(relation)
Definition: rel.h:462
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:71
#define ereport(elevel, rest)
Definition: elog.h:141
TupleDesc rd_att
Definition: rel.h:85
#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:822
#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 15814 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().

15816 {
15817  List *existConstraint = NIL;
15818  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
15819  int i;
15820 
15821  if (constr && constr->has_not_null)
15822  {
15823  int natts = scanrel->rd_att->natts;
15824 
15825  for (i = 1; i <= natts; i++)
15826  {
15827  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
15828 
15829  if (att->attnotnull && !att->attisdropped)
15830  {
15831  NullTest *ntest = makeNode(NullTest);
15832 
15833  ntest->arg = (Expr *) makeVar(1,
15834  i,
15835  att->atttypid,
15836  att->atttypmod,
15837  att->attcollation,
15838  0);
15839  ntest->nulltesttype = IS_NOT_NULL;
15840 
15841  /*
15842  * argisrow=false is correct even for a composite column,
15843  * because attnotnull does not represent a SQL-spec IS NOT
15844  * NULL test in such a case, just IS DISTINCT FROM NULL.
15845  */
15846  ntest->argisrow = false;
15847  ntest->location = -1;
15848  existConstraint = lappend(existConstraint, ntest);
15849  }
15850  }
15851  }
15852 
15853  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
15854 }
#define NIL
Definition: pg_list.h:65
#define RelationGetDescr(relation)
Definition: rel.h:454
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Expr * arg
Definition: primnodes.h:1219
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
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:322
TupleDesc rd_att
Definition: rel.h:85
NullTestType nulltesttype
Definition: primnodes.h:1220
#define makeNode(_type_)
Definition: nodes.h:573
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:15867
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 15104 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().

15105 {
15106  ListCell *l;
15107  List *oids_to_truncate = NIL;
15108  List *oids_to_drop = NIL;
15109 
15110  foreach(l, on_commits)
15111  {
15112  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
15113 
15114  /* Ignore entry if already dropped in this xact */
15116  continue;
15117 
15118  switch (oc->oncommit)
15119  {
15120  case ONCOMMIT_NOOP:
15122  /* Do nothing (there shouldn't be such entries, actually) */
15123  break;
15124  case ONCOMMIT_DELETE_ROWS:
15125 
15126  /*
15127  * If this transaction hasn't accessed any temporary
15128  * relations, we can skip truncating ON COMMIT DELETE ROWS
15129  * tables, as they must still be empty.
15130  */
15132  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
15133  break;
15134  case ONCOMMIT_DROP:
15135  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
15136  break;
15137  }
15138  }
15139 
15140  /*
15141  * Truncate relations before dropping so that all dependencies between
15142  * relations are removed after they are worked on. Doing it like this
15143  * might be a waste as it is possible that a relation being truncated will
15144  * be dropped anyway due to its parent being dropped, but this makes the
15145  * code more robust because of not having to re-check that the relation
15146  * exists at truncation time.
15147  */
15148  if (oids_to_truncate != NIL)
15149  heap_truncate(oids_to_truncate);
15150 
15151  if (oids_to_drop != NIL)
15152  {
15153  ObjectAddresses *targetObjects = new_object_addresses();
15154  ListCell *l;
15155 
15156  foreach(l, oids_to_drop)
15157  {
15158  ObjectAddress object;
15159 
15160  object.classId = RelationRelationId;
15161  object.objectId = lfirst_oid(l);
15162  object.objectSubId = 0;
15163 
15164  Assert(!object_address_present(&object, targetObjects));
15165 
15166  add_exact_object_address(&object, targetObjects);
15167  }
15168 
15169  /*
15170  * Since this is an automatic drop, rather than one directly initiated
15171  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
15172  */
15173  performMultipleDeletions(targetObjects, DROP_CASCADE,
15175 
15176 #ifdef USE_ASSERT_CHECKING
15177 
15178  /*
15179  * Note that table deletion will call remove_on_commit_action, so the
15180  * entry should get marked as deleted.
15181  */
15182  foreach(l, on_commits)
15183  {
15184  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
15185 
15186  if (oc->oncommit != ONCOMMIT_DROP)
15187  continue;
15188 
15190  }
15191 #endif
15192  }
15193 }
#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:2529
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2469
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2414
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
static List * on_commits
Definition: tablecmds.c:122
int MyXactFlags
Definition: xact.c:118
#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:3216
#define InvalidSubTransactionId
Definition: c.h:519
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:374
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 15327 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().

15329 {
15330  HeapTuple tuple;
15331 
15332  /* Nothing to do if the relation was not found. */
15333  if (!OidIsValid(relId))
15334  return;
15335 
15336  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
15337  if (!HeapTupleIsValid(tuple)) /* should not happen */
15338  elog(ERROR, "cache lookup failed for relation %u", relId);
15339 
15340  if (!pg_class_ownercheck(relId, GetUserId()))
15342  relation->relname);
15343 
15344  if (!allowSystemTableMods &&
15345  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
15346  ereport(ERROR,
15347  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
15348  errmsg("permission denied: \"%s\" is a system catalog",
15349  relation->relname)));
15350 
15351  ReleaseSysCache(tuple);
15352 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Oid GetUserId(void)
Definition: miscinit.c:378
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
int errcode(int sqlerrcode)
Definition: elog.c:608
#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:3352
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
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 HeapTupleIsValid(tuple)
Definition: htup.h:78
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4753
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
ObjectType get_relkind_objtype(char relkind)

◆ RangeVarCallbackOwnsTable()

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

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

15273 {
15274  char relkind;
15275 
15276  /* Nothing to do if the relation was not found. */
15277  if (!OidIsValid(relId))
15278  return;
15279 
15280  /*
15281  * If the relation does exist, check whether it's an index. But note that
15282  * the relation might have been dropped between the time we did the name
15283  * lookup and now. In that case, there's nothing to do.
15284  */
15285  relkind = get_rel_relkind(relId);
15286  if (!relkind)
15287  return;
15288  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
15289  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
15290  ereport(ERROR,
15291  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15292  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
15293 
15294  /* Check permissions */
15295  if (!pg_class_ownercheck(relId, GetUserId()))
15297 }
Oid GetUserId(void)
Definition: miscinit.c:378
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
int errcode(int sqlerrcode)
Definition: elog.c:608
#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:3352
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4753
int errmsg(const char *fmt,...)
Definition: elog.c:822
ObjectType get_relkind_objtype(char relkind)

◆ register_on_commit_action()

void register_on_commit_action ( Oid  relid,
OnCommitAction  action 
)

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

15046 {
15047  OnCommitItem *oc;
15048  MemoryContext oldcxt;
15049 
15050  /*
15051  * We needn't bother registering the relation unless there is an ON COMMIT
15052  * action we need to take.
15053  */
15055  return;
15056 
15058 
15059  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
15060  oc->relid = relid;
15061  oc->oncommit = action;
15064 
15065  /*
15066  * We use lcons() here so that ON COMMIT actions are processed in reverse
15067  * order of registration. That might not be essential but it seems
15068  * reasonable.
15069  */
15070  on_commits = lcons(oc, on_commits);
15071 
15072  MemoryContextSwitchTo(oldcxt);
15073 }
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:454
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:707
#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 15081 of file tablecmds.c.

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

Referenced by heap_drop_with_catalog().

15082 {
15083  ListCell *l;
15084 
15085  foreach(l, on_commits)
15086  {
15087  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
15088 
15089  if (oc->relid == relid)
15090  {
15092  break;
15093  }
15094  }
15095 }
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:707

◆ RemoveRelations()

void RemoveRelations ( DropStmt drop)

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

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

◆ renameatt()

ObjectAddress renameatt ( RenameStmt stmt)

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

3142 {
3143  Oid relid;
3145  ObjectAddress address;
3146 
3147  /* lock level taken here should match renameatt_internal */
3149  stmt->missing_ok ? RVR_MISSING_OK : 0,
3151  NULL);
3152 
3153  if (!OidIsValid(relid))
3154  {
3155  ereport(NOTICE,
3156  (errmsg("relation \"%s\" does not exist, skipping",
3157  stmt->relation->relname)));
3158  return InvalidObjectAddress;
3159  }
3160 
3161  attnum =
3162  renameatt_internal(relid,
3163  stmt->subname, /* old att name */
3164  stmt->newname, /* new att name */
3165  stmt->relation->inh, /* recursive? */
3166  false, /* recursing? */
3167  0, /* expected inhcount */
3168  stmt->behavior);
3169 
3170  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3171 
3172  return address;
3173 }
char * subname
Definition: parsenodes.h:2915
char * newname
Definition: parsenodes.h:2917
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:2919
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:228
#define ereport(elevel, rest)
Definition: elog.h:141
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:2913
int16 attnum
Definition: pg_attribute.h:79
#define NOTICE
Definition: elog.h:37
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3121
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:2976
#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:822
DropBehavior behavior
Definition: parsenodes.h:2918
int16 AttrNumber
Definition: attnum.h:21

◆ RenameConstraint()

ObjectAddress RenameConstraint ( RenameStmt stmt)

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

3286 {
3287  Oid relid = InvalidOid;
3288  Oid typid = InvalidOid;
3289 
3290  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3291  {
3292  Relation rel;
3293  HeapTuple tup;
3294 
3296  rel = table_open(TypeRelationId, RowExclusiveLock);
3297  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3298  if (!HeapTupleIsValid(tup))
3299  elog(ERROR, "cache lookup failed for type %u", typid);
3300  checkDomainOwner(tup);
3301  ReleaseSysCache(tup);
3302  table_close(rel, NoLock);
3303  }
3304  else
3305  {
3306  /* lock level taken here should match rename_constraint_internal */
3308  stmt->missing_ok ? RVR_MISSING_OK : 0,
3310  NULL);
3311  if (!OidIsValid(relid))
3312  {
3313  ereport(NOTICE,
3314  (errmsg("relation \"%s\" does not exist, skipping",
3315  stmt->relation->relname)));
3316  return InvalidObjectAddress;
3317  }
3318  }
3319 
3320  return
3321  rename_constraint_internal(relid, typid,
3322  stmt->subname,
3323  stmt->newname,
3324  (stmt->relation &&
3325  stmt->relation->inh), /* recursive? */
3326  false, /* recursing? */
3327  0 /* expected inhcount */ );
3328 
3329 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
char * subname
Definition: parsenodes.h:2915
ObjectType renameType
Definition: parsenodes.h:2911
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
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:3179
char * newname
Definition: parsenodes.h:2917
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:2919
#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:2914
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:228
#define ereport(elevel, rest)
Definition: elog.h:141
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:2913
#define InvalidOid
Definition: postgres_ext.h:36
#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:3121
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3047
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
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 3336 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().

3337 {
3338  bool is_index = stmt->renameType == OBJECT_INDEX;
3339  Oid relid;
3340  ObjectAddress address;
3341 
3342  /*
3343  * Grab an exclusive lock on the target table, index, sequence, view,
3344  * materialized view, or foreign table, which we will NOT release until
3345  * end of transaction.
3346  *
3347  * Lock level used here should match RenameRelationInternal, to avoid lock
3348  * escalation.
3349  */
3350  relid = RangeVarGetRelidExtended(stmt->relation,
3352  stmt->missing_ok ? RVR_MISSING_OK : 0,
3354  (void *) stmt);
3355 
3356  if (!OidIsValid(relid))
3357  {
3358  ereport(NOTICE,
3359  (errmsg("relation \"%s\" does not exist, skipping",
3360  stmt->relation->relname)));
3361  return InvalidObjectAddress;
3362  }
3363 
3364  /* Do the work */
3365  RenameRelationInternal(relid, stmt->newname, false, is_index);
3366 
3367  ObjectAddressSet(address, RelationRelationId, relid);
3368 
3369  return address;
3370 }
ObjectType renameType
Definition: parsenodes.h:2911
char * newname
Definition: parsenodes.h:2917
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:2919
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:15359
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:228
#define ereport(elevel, rest)
Definition: elog.h:141
RangeVar * relation
Definition: parsenodes.h:2913
#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:822
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3376

◆ RenameRelationInternal()

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

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

3377 {
3378  Relation targetrelation;
3379  Relation relrelation; /* for RELATION relation */
3380  HeapTuple reltup;
3381  Form_pg_class relform;
3382  Oid namespaceId;
3383 
3384  /*
3385  * Grab a lock on the target relation, which we will NOT release until end
3386  * of transaction. We need at least a self-exclusive lock so that
3387  * concurrent DDL doesn't overwrite the rename if they start updating
3388  * while still seeing the old version. The lock also guards against
3389  * triggering relcache reloads in concurrent sessions, which might not
3390  * handle this information changing under them. For indexes, we can use a
3391  * reduced lock level because RelationReloadIndexInfo() handles indexes
3392  * specially.
3393  */
3394  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
3395  namespaceId = RelationGetNamespace(targetrelation);
3396 
3397  /*
3398  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3399  */
3400  relrelation = table_open(RelationRelationId, RowExclusiveLock);
3401 
3402  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3403  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3404  elog(ERROR, "cache lookup failed for relation %u", myrelid);
3405  relform = (Form_pg_class) GETSTRUCT(reltup);
3406 
3407  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3408  ereport(ERROR,
3409  (errcode(ERRCODE_DUPLICATE_TABLE),
3410  errmsg("relation \"%s\" already exists",
3411  newrelname)));
3412 
3413  /*
3414  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
3415  * because it's a copy...)
3416  */
3417  namestrcpy(&(relform->relname), newrelname);
3418 
3419  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3420 
3421  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
3422  InvalidOid, is_internal);
3423 
3424  heap_freetuple(reltup);
3425  table_close(relrelation, RowExclusiveLock);
3426 
3427  /*
3428  * Also rename the associated type, if any.
3429  */
3430  if (OidIsValid(targetrelation->rd_rel->reltype))
3431  RenameTypeInternal(targetrelation->rd_rel->reltype,
3432  newrelname, namespaceId);
3433 
3434  /*
3435  * Also rename the associated constraint, if any.
3436  */
3437  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3438  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3439  {
3440  Oid constraintId = get_index_constraint(myrelid);
3441 
3442  if (OidIsValid(constraintId))
3443  RenameConstraintById(constraintId, newrelname);
3444  }
3445 
3446  /*
3447  * Close rel, but keep lock!
3448  */
3449  relation_close(targetrelation, NoLock);
3450 }
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:608
Form_pg_class rd_rel
Definition: rel.h:84
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:1687
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:873
#define ereport(elevel, rest)
Definition: elog.h:141
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:709
#define InvalidOid
Definition: postgres_ext.h:36
#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:822
#define elog(elevel,...)
Definition: elog.h:228
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetNamespace(relation)
Definition: rel.h:469

◆ SetRelationHasSubclass()

void SetRelationHasSubclass ( Oid  relationId,
bool  relhassubclass 
)

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

2895 {
2896  Relation relationRelation;
2897  HeapTuple tuple;
2898  Form_pg_class classtuple;
2899 
2900  /*
2901  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
2902  */
2903  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
2904  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
2905  if (!HeapTupleIsValid(tuple))
2906  elog(ERROR, "cache lookup failed for relation %u", relationId);
2907  classtuple = (Form_pg_class) GETSTRUCT(tuple);
2908 
2909  if (classtuple->relhassubclass != relhassubclass)
2910  {
2911  classtuple->relhassubclass = relhassubclass;
2912  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
2913  }
2914  else
2915  {
2916  /* no need to change tuple, but force relcache rebuild anyway */
2918  }
2919 
2920  heap_freetuple(tuple);
2921  table_close(relationRelation, RowExclusiveLock);
2922 }
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:228
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1306
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39