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 (Oid relid, LOCKMODE lockmode, AlterTableStmt *stmt)
 
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 14359 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().

14363 {
14364  HeapTuple classTup;
14365  Form_pg_class classForm;
14366  ObjectAddress thisobj;
14367  bool already_done = false;
14368 
14369  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
14370  if (!HeapTupleIsValid(classTup))
14371  elog(ERROR, "cache lookup failed for relation %u", relOid);
14372  classForm = (Form_pg_class) GETSTRUCT(classTup);
14373 
14374  Assert(classForm->relnamespace == oldNspOid);
14375 
14376  thisobj.classId = RelationRelationId;
14377  thisobj.objectId = relOid;
14378  thisobj.objectSubId = 0;
14379 
14380  /*
14381  * If the object has already been moved, don't move it again. If it's
14382  * already in the right place, don't move it, but still fire the object
14383  * access hook.
14384  */
14385  already_done = object_address_present(&thisobj, objsMoved);
14386  if (!already_done && oldNspOid != newNspOid)
14387  {
14388  /* check for duplicate name (more friendly than unique-index failure) */
14389  if (get_relname_relid(NameStr(classForm->relname),
14390  newNspOid) != InvalidOid)
14391  ereport(ERROR,
14392  (errcode(ERRCODE_DUPLICATE_TABLE),
14393  errmsg("relation \"%s\" already exists in schema \"%s\"",
14394  NameStr(classForm->relname),
14395  get_namespace_name(newNspOid))));
14396 
14397  /* classTup is a copy, so OK to scribble on */
14398  classForm->relnamespace = newNspOid;
14399 
14400  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
14401 
14402  /* Update dependency on schema if caller said so */
14403  if (hasDependEntry &&
14404  changeDependencyFor(RelationRelationId,
14405  relOid,
14406  NamespaceRelationId,
14407  oldNspOid,
14408  newNspOid) != 1)
14409  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
14410  NameStr(classForm->relname));
14411  }
14412  if (!already_done)
14413  {
14414  add_exact_object_address(&thisobj, objsMoved);
14415 
14416  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
14417  }
14418 
14419  heap_freetuple(classTup);
14420 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2517
int errcode(int sqlerrcode)
Definition: elog.c:608
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2457
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:739
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
#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:616

◆ AlterTable()

void AlterTable ( Oid  relid,
LOCKMODE  lockmode,
AlterTableStmt stmt 
)

Definition at line 3502 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3503 {
3504  Relation rel;
3505 
3506  /* Caller is required to provide an adequate lock. */
3507  rel = relation_open(relid, NoLock);
3508 
3509  CheckTableNotInUse(rel, "ALTER TABLE");
3510 
3511  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode);
3512 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3832
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:3423
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1753

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 3571 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_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_ProcessedConstraint, 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().

3572 {
3573  /*
3574  * This only works if we read catalog tables using MVCC snapshots.
3575  */
3576  ListCell *lcmd;
3578 
3579  foreach(lcmd, cmds)
3580  {
3581  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3582  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
3583 
3584  switch (cmd->subtype)
3585  {
3586  /*
3587  * These subcommands rewrite the heap, so require full locks.
3588  */
3589  case AT_AddColumn: /* may rewrite heap, in some cases and visible
3590  * to SELECT */
3591  case AT_SetTableSpace: /* must rewrite heap */
3592  case AT_AlterColumnType: /* must rewrite heap */
3593  cmd_lockmode = AccessExclusiveLock;
3594  break;
3595 
3596  /*
3597  * These subcommands may require addition of toast tables. If
3598  * we add a toast table to a table currently being scanned, we
3599  * might miss data added to the new toast table by concurrent
3600  * insert transactions.
3601  */
3602  case AT_SetStorage: /* may add toast tables, see
3603  * ATRewriteCatalogs() */
3604  cmd_lockmode = AccessExclusiveLock;
3605  break;
3606 
3607  /*
3608  * Removing constraints can affect SELECTs that have been
3609  * optimized assuming the constraint holds true. See also
3610  * CloneFkReferenced.
3611  */
3612  case AT_DropConstraint: /* as DROP INDEX */
3613  case AT_DropNotNull: /* may change some SQL plans */
3614  cmd_lockmode = AccessExclusiveLock;
3615  break;
3616 
3617  /*
3618  * Subcommands that may be visible to concurrent SELECTs
3619  */
3620  case AT_DropColumn: /* change visible to SELECT */
3621  case AT_AddColumnToView: /* CREATE VIEW */
3622  case AT_DropOids: /* used to equiv to DropColumn */
3623  case AT_EnableAlwaysRule: /* may change SELECT rules */
3624  case AT_EnableReplicaRule: /* may change SELECT rules */
3625  case AT_EnableRule: /* may change SELECT rules */
3626  case AT_DisableRule: /* may change SELECT rules */
3627  cmd_lockmode = AccessExclusiveLock;
3628  break;
3629 
3630  /*
3631  * Changing owner may remove implicit SELECT privileges
3632  */
3633  case AT_ChangeOwner: /* change visible to SELECT */
3634  cmd_lockmode = AccessExclusiveLock;
3635  break;
3636 
3637  /*
3638  * Changing foreign table options may affect optimization.
3639  */
3640  case AT_GenericOptions:
3642  cmd_lockmode = AccessExclusiveLock;
3643  break;
3644 
3645  /*
3646  * These subcommands affect write operations only.
3647  */
3648  case AT_EnableTrig:
3649  case AT_EnableAlwaysTrig:
3650  case AT_EnableReplicaTrig:
3651  case AT_EnableTrigAll:
3652  case AT_EnableTrigUser:
3653  case AT_DisableTrig:
3654  case AT_DisableTrigAll:
3655  case AT_DisableTrigUser:
3656  cmd_lockmode = ShareRowExclusiveLock;
3657  break;
3658 
3659  /*
3660  * These subcommands affect write operations only. XXX
3661  * Theoretically, these could be ShareRowExclusiveLock.
3662  */
3663  case AT_ColumnDefault:
3664  case AT_AlterConstraint:
3665  case AT_AddIndex: /* from ADD CONSTRAINT */
3666  case AT_AddIndexConstraint:
3667  case AT_ReplicaIdentity:
3668  case AT_SetNotNull:
3669  case AT_EnableRowSecurity:
3670  case AT_DisableRowSecurity:
3671  case AT_ForceRowSecurity:
3672  case AT_NoForceRowSecurity:
3673  case AT_AddIdentity:
3674  case AT_DropIdentity:
3675  case AT_SetIdentity:
3676  cmd_lockmode = AccessExclusiveLock;
3677  break;
3678 
3679  case AT_AddConstraint:
3680  case AT_ProcessedConstraint: /* becomes AT_AddConstraint */
3681  case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
3682  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
3683  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
3684  if (IsA(cmd->def, Constraint))
3685  {
3686  Constraint *con = (Constraint *) cmd->def;
3687 
3688  switch (con->contype)
3689  {
3690  case CONSTR_EXCLUSION:
3691  case CONSTR_PRIMARY:
3692  case CONSTR_UNIQUE:
3693 
3694  /*
3695  * Cases essentially the same as CREATE INDEX. We
3696  * could reduce the lock strength to ShareLock if
3697  * we can work out how to allow concurrent catalog
3698  * updates. XXX Might be set down to
3699  * ShareRowExclusiveLock but requires further
3700  * analysis.
3701  */
3702  cmd_lockmode = AccessExclusiveLock;
3703  break;
3704  case CONSTR_FOREIGN:
3705 
3706  /*
3707  * We add triggers to both tables when we add a
3708  * Foreign Key, so the lock level must be at least
3709  * as strong as CREATE TRIGGER.
3710  */
3711  cmd_lockmode = ShareRowExclusiveLock;
3712  break;
3713 
3714  default:
3715  cmd_lockmode = AccessExclusiveLock;
3716  }
3717  }
3718  break;
3719 
3720  /*
3721  * These subcommands affect inheritance behaviour. Queries
3722  * started before us will continue to see the old inheritance
3723  * behaviour, while queries started after we commit will see
3724  * new behaviour. No need to prevent reads or writes to the
3725  * subtable while we hook it up though. Changing the TupDesc
3726  * may be a problem, so keep highest lock.
3727  */
3728  case AT_AddInherit:
3729  case AT_DropInherit:
3730  cmd_lockmode = AccessExclusiveLock;
3731  break;
3732 
3733  /*
3734  * These subcommands affect implicit row type conversion. They
3735  * have affects similar to CREATE/DROP CAST on queries. don't
3736  * provide for invalidating parse trees as a result of such
3737  * changes, so we keep these at AccessExclusiveLock.
3738  */
3739  case AT_AddOf:
3740  case AT_DropOf:
3741  cmd_lockmode = AccessExclusiveLock;
3742  break;
3743 
3744  /*
3745  * Only used by CREATE OR REPLACE VIEW which must conflict
3746  * with an SELECTs currently using the view.
3747  */
3748  case AT_ReplaceRelOptions:
3749  cmd_lockmode = AccessExclusiveLock;
3750  break;
3751 
3752  /*
3753  * These subcommands affect general strategies for performance
3754  * and maintenance, though don't change the semantic results
3755  * from normal data reads and writes. Delaying an ALTER TABLE
3756  * behind currently active writes only delays the point where
3757  * the new strategy begins to take effect, so there is no
3758  * benefit in waiting. In this case the minimum restriction
3759  * applies: we don't currently allow concurrent catalog
3760  * updates.
3761  */
3762  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
3763  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
3764  case AT_DropCluster: /* Uses MVCC in getIndexes() */
3765  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
3766  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
3767  cmd_lockmode = ShareUpdateExclusiveLock;
3768  break;
3769 
3770  case AT_SetLogged:
3771  case AT_SetUnLogged:
3772  cmd_lockmode = AccessExclusiveLock;
3773  break;
3774 
3775  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
3776  cmd_lockmode = ShareUpdateExclusiveLock;
3777  break;
3778 
3779  /*
3780  * Rel options are more complex than first appears. Options
3781  * are set here for tables, views and indexes; for historical
3782  * reasons these can all be used with ALTER TABLE, so we can't
3783  * decide between them using the basic grammar.
3784  */
3785  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
3786  * getTables() */
3787  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
3788  * getTables() */
3789  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
3790  break;
3791 
3792  case AT_AttachPartition:
3793  cmd_lockmode = ShareUpdateExclusiveLock;
3794  break;
3795 
3796  case AT_DetachPartition:
3797  cmd_lockmode = AccessExclusiveLock;
3798  break;
3799 
3800  case AT_CheckNotNull:
3801 
3802  /*
3803  * This only examines the table's schema; but lock must be
3804  * strong enough to prevent concurrent DROP NOT NULL.
3805  */
3806  cmd_lockmode = AccessShareLock;
3807  break;
3808 
3809  default: /* oops */
3810  elog(ERROR, "unrecognized alter table type: %d",
3811  (int) cmd->subtype);
3812  break;
3813  }
3814 
3815  /*
3816  * Take the greatest lockmode from any subcommand
3817  */
3818  if (cmd_lockmode > lockmode)
3819  lockmode = cmd_lockmode;
3820  }
3821 
3822  return lockmode;
3823 }
#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:1840
#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:2129
Definition: pg_list.h:50

◆ AlterTableInternal()

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

Definition at line 3526 of file tablecmds.c.

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

3527 {
3528  Relation rel;
3529  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
3530 
3531  rel = relation_open(relid, lockmode);
3532 
3534 
3535  ATController(NULL, rel, cmds, recurse, lockmode);
3536 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3832
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:3571
void EventTriggerAlterTableRelid(Oid objectId)

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3451 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3452 {
3453  return RangeVarGetRelidExtended(stmt->relation, lockmode,
3454  stmt->missing_ok ? RVR_MISSING_OK : 0,
3456  (void *) stmt);
3457 }
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:14872
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:228
RangeVar * relation
Definition: parsenodes.h:1753

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

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

12555 {
12556  List *relations = NIL;
12557  ListCell *l;
12558  ScanKeyData key[1];
12559  Relation rel;
12560  TableScanDesc scan;
12561  HeapTuple tuple;
12562  Oid orig_tablespaceoid;
12563  Oid new_tablespaceoid;
12564  List *role_oids = roleSpecsToIds(stmt->roles);
12565 
12566  /* Ensure we were not asked to move something we can't */
12567  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
12568  stmt->objtype != OBJECT_MATVIEW)
12569  ereport(ERROR,
12570  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
12571  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
12572 
12573  /* Get the orig and new tablespace OIDs */
12574  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
12575  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
12576 
12577  /* Can't move shared relations in to or out of pg_global */
12578  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
12579  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
12580  new_tablespaceoid == GLOBALTABLESPACE_OID)
12581  ereport(ERROR,
12582  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
12583  errmsg("cannot move relations in to or out of pg_global tablespace")));
12584 
12585  /*
12586  * Must have CREATE rights on the new tablespace, unless it is the
12587  * database default tablespace (which all users implicitly have CREATE
12588  * rights on).
12589  */
12590  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
12591  {
12592  AclResult aclresult;
12593 
12594  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
12595  ACL_CREATE);
12596  if (aclresult != ACLCHECK_OK)
12597  aclcheck_error(aclresult, OBJECT_TABLESPACE,
12598  get_tablespace_name(new_tablespaceoid));
12599  }
12600 
12601  /*
12602  * Now that the checks are done, check if we should set either to
12603  * InvalidOid because it is our database's default tablespace.
12604  */
12605  if (orig_tablespaceoid == MyDatabaseTableSpace)
12606  orig_tablespaceoid = InvalidOid;
12607 
12608  if (new_tablespaceoid == MyDatabaseTableSpace)
12609  new_tablespaceoid = InvalidOid;
12610 
12611  /* no-op */
12612  if (orig_tablespaceoid == new_tablespaceoid)
12613  return new_tablespaceoid;
12614 
12615  /*
12616  * Walk the list of objects in the tablespace and move them. This will
12617  * only find objects in our database, of course.
12618  */
12619  ScanKeyInit(&key[0],
12620  Anum_pg_class_reltablespace,
12621  BTEqualStrategyNumber, F_OIDEQ,
12622  ObjectIdGetDatum(orig_tablespaceoid));
12623 
12624  rel = table_open(RelationRelationId, AccessShareLock);
12625  scan = table_beginscan_catalog(rel, 1, key);
12626  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
12627  {
12628  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
12629  Oid relOid = relForm->oid;
12630 
12631  /*
12632  * Do not move objects in pg_catalog as part of this, if an admin
12633  * really wishes to do so, they can issue the individual ALTER
12634  * commands directly.
12635  *
12636  * Also, explicitly avoid any shared tables, temp tables, or TOAST
12637  * (TOAST will be moved with the main table).
12638  */
12639  if (IsCatalogNamespace(relForm->relnamespace) ||
12640  relForm->relisshared ||
12641  isAnyTempNamespace(relForm->relnamespace) ||
12642  IsToastNamespace(relForm->relnamespace))
12643  continue;
12644 
12645  /* Only move the object type requested */
12646  if ((stmt->objtype == OBJECT_TABLE &&
12647  relForm->relkind != RELKIND_RELATION &&
12648  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
12649  (stmt->objtype == OBJECT_INDEX &&
12650  relForm->relkind != RELKIND_INDEX &&
12651  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
12652  (stmt->objtype == OBJECT_MATVIEW &&
12653  relForm->relkind != RELKIND_MATVIEW))
12654  continue;
12655 
12656  /* Check if we are only moving objects owned by certain roles */
12657  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
12658  continue;
12659 
12660  /*
12661  * Handle permissions-checking here since we are locking the tables
12662  * and also to avoid doing a bunch of work only to fail part-way. Note
12663  * that permissions will also be checked by AlterTableInternal().
12664  *
12665  * Caller must be considered an owner on the table to move it.
12666  */
12667  if (!pg_class_ownercheck(relOid, GetUserId()))
12669  NameStr(relForm->relname));
12670 
12671  if (stmt->nowait &&
12673  ereport(ERROR,
12674  (errcode(ERRCODE_OBJECT_IN_USE),
12675  errmsg("aborting because lock on relation \"%s.%s\" is not available",
12676  get_namespace_name(relForm->relnamespace),
12677  NameStr(relForm->relname))));
12678  else
12680 
12681  /* Add to our list of objects to move */
12682  relations = lappend_oid(relations, relOid);
12683  }
12684 
12685  table_endscan(scan);
12687 
12688  if (relations == NIL)
12689  ereport(NOTICE,
12690  (errcode(ERRCODE_NO_DATA_FOUND),
12691  errmsg("no matching relations in tablespace \"%s\" found",
12692  orig_tablespaceoid == InvalidOid ? "(database default)" :
12693  get_tablespace_name(orig_tablespaceoid))));
12694 
12695  /* Everything is locked, loop through and move all of the relations. */
12696  foreach(l, relations)
12697  {
12698  List *cmds = NIL;
12700 
12701  cmd->subtype = AT_SetTableSpace;
12702  cmd->name = stmt->new_tablespacename;
12703 
12704  cmds = lappend(cmds, cmd);
12705 
12707  /* OID is set by AlterTableInternal */
12708  AlterTableInternal(lfirst_oid(l), cmds, false);
12710  }
12711 
12712  return new_tablespaceoid;
12713 }
#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:380
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:1840
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:196
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:645
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:1290
#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:178
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:831
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:3526
#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:616
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 14250 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().

14251 {
14252  Relation rel;
14253  Oid relid;
14254  Oid oldNspOid;
14255  Oid nspOid;
14256  RangeVar *newrv;
14257  ObjectAddresses *objsMoved;
14258  ObjectAddress myself;
14259 
14261  stmt->missing_ok ? RVR_MISSING_OK : 0,
14263  (void *) stmt);
14264 
14265  if (!OidIsValid(relid))
14266  {
14267  ereport(NOTICE,
14268  (errmsg("relation \"%s\" does not exist, skipping",
14269  stmt->relation->relname)));
14270  return InvalidObjectAddress;
14271  }
14272 
14273  rel = relation_open(relid, NoLock);
14274 
14275  oldNspOid = RelationGetNamespace(rel);
14276 
14277  /* If it's an owned sequence, disallow moving it by itself. */
14278  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
14279  {
14280  Oid tableId;
14281  int32 colId;
14282 
14283  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
14284  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
14285  ereport(ERROR,
14286  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14287  errmsg("cannot move an owned sequence into another schema"),
14288  errdetail("Sequence \"%s\" is linked to table \"%s\".",
14290  get_rel_name(tableId))));
14291  }
14292 
14293  /* Get and lock schema OID and check its permissions. */
14294  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
14295  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
14296 
14297  /* common checks on switching namespaces */
14298  CheckSetNamespace(oldNspOid, nspOid);
14299 
14300  objsMoved = new_object_addresses();
14301  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
14302  free_object_addresses(objsMoved);
14303 
14304  ObjectAddressSet(myself, RelationRelationId, relid);
14305 
14306  if (oldschema)
14307  *oldschema = oldNspOid;
14308 
14309  /* close rel, but keep lock until commit */
14310  relation_close(rel, NoLock);
14311 
14312  return myself;
14313 }
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:2402
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2697
Form_pg_class rd_rel
Definition: rel.h:83
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
signed int int32
Definition: c.h:347
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:14321
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:14872
int errdetail(const char *fmt,...)
Definition: elog.c:955
#define RelationGetRelationName(relation)
Definition: rel.h:456
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:463

◆ AlterTableNamespaceInternal()

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

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

14323 {
14324  Relation classRel;
14325 
14326  Assert(objsMoved != NULL);
14327 
14328  /* OK, modify the pg_class row and pg_depend entry */
14329  classRel = table_open(RelationRelationId, RowExclusiveLock);
14330 
14331  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
14332  nspOid, true, objsMoved);
14333 
14334  /* Fix the table's row type too */
14335  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
14336  nspOid, false, false, objsMoved);
14337 
14338  /* Fix other dependent stuff */
14339  if (rel->rd_rel->relkind == RELKIND_RELATION ||
14340  rel->rd_rel->relkind == RELKIND_MATVIEW ||
14341  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14342  {
14343  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
14344  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
14345  objsMoved, AccessExclusiveLock);
14346  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
14347  false, objsMoved);
14348  }
14349 
14350  table_close(classRel, RowExclusiveLock);
14351 }
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:83
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:14429
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:14474
#define RowExclusiveLock
Definition: lockdefs.h:38
#define Assert(condition)
Definition: c.h:739
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:14359
#define AccessExclusiveLock
Definition: lockdefs.h:45
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:422

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 14750 of file tablecmds.c.

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

14752 {
14753  ListCell *cur_item;
14754 
14755  foreach(cur_item, on_commits)
14756  {
14757  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
14758 
14759  if (!isCommit && oc->creating_subid == mySubid)
14760  {
14761  /* cur_item must be removed */
14763  pfree(oc);
14764  }
14765  else
14766  {
14767  /* cur_item must be preserved */
14768  if (oc->creating_subid == mySubid)
14769  oc->creating_subid = parentSubid;
14770  if (oc->deleting_subid == mySubid)
14771  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
14772  }
14773  }
14774 }
SubTransactionId creating_subid
Definition: tablecmds.c:117
#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:121
SubTransactionId deleting_subid
Definition: tablecmds.c:118
#define lfirst(lc)
Definition: pg_list.h:190
#define InvalidSubTransactionId
Definition: c.h:520

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 14718 of file tablecmds.c.

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

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

14719 {
14720  ListCell *cur_item;
14721 
14722  foreach(cur_item, on_commits)
14723  {
14724  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
14725 
14726  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
14728  {
14729  /* cur_item must be removed */
14731  pfree(oc);
14732  }
14733  else
14734  {
14735  /* cur_item must be preserved */
14738  }
14739  }
14740 }
SubTransactionId creating_subid
Definition: tablecmds.c:117
#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:121
SubTransactionId deleting_subid
Definition: tablecmds.c:118
#define lfirst(lc)
Definition: pg_list.h:190
#define InvalidSubTransactionId
Definition: c.h:520

◆ ATExecChangeOwner()

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

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

11703 {
11704  Relation target_rel;
11705  Relation class_rel;
11706  HeapTuple tuple;
11707  Form_pg_class tuple_class;
11708 
11709  /*
11710  * Get exclusive lock till end of transaction on the target table. Use
11711  * relation_open so that we can work on indexes and sequences.
11712  */
11713  target_rel = relation_open(relationOid, lockmode);
11714 
11715  /* Get its pg_class tuple, too */
11716  class_rel = table_open(RelationRelationId, RowExclusiveLock);
11717 
11718  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
11719  if (!HeapTupleIsValid(tuple))
11720  elog(ERROR, "cache lookup failed for relation %u", relationOid);
11721  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
11722 
11723  /* Can we change the ownership of this tuple? */
11724  switch (tuple_class->relkind)
11725  {
11726  case RELKIND_RELATION:
11727  case RELKIND_VIEW:
11728  case RELKIND_MATVIEW:
11729  case RELKIND_FOREIGN_TABLE:
11730  case RELKIND_PARTITIONED_TABLE:
11731  /* ok to change owner */
11732  break;
11733  case RELKIND_INDEX:
11734  if (!recursing)
11735  {
11736  /*
11737  * Because ALTER INDEX OWNER used to be allowed, and in fact
11738  * is generated by old versions of pg_dump, we give a warning
11739  * and do nothing rather than erroring out. Also, to avoid
11740  * unnecessary chatter while restoring those old dumps, say
11741  * nothing at all if the command would be a no-op anyway.
11742  */
11743  if (tuple_class->relowner != newOwnerId)
11744  ereport(WARNING,
11745  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11746  errmsg("cannot change owner of index \"%s\"",
11747  NameStr(tuple_class->relname)),
11748  errhint("Change the ownership of the index's table, instead.")));
11749  /* quick hack to exit via the no-op path */
11750  newOwnerId = tuple_class->relowner;
11751  }
11752  break;
11753  case RELKIND_PARTITIONED_INDEX:
11754  if (recursing)
11755  break;
11756  ereport(ERROR,
11757  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11758  errmsg("cannot change owner of index \"%s\"",
11759  NameStr(tuple_class->relname)),
11760  errhint("Change the ownership of the index's table, instead.")));
11761  break;
11762  case RELKIND_SEQUENCE:
11763  if (!recursing &&
11764  tuple_class->relowner != newOwnerId)
11765  {
11766  /* if it's an owned sequence, disallow changing it by itself */
11767  Oid tableId;
11768  int32 colId;
11769 
11770  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
11771  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
11772  ereport(ERROR,
11773  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11774  errmsg("cannot change owner of sequence \"%s\"",
11775  NameStr(tuple_class->relname)),
11776  errdetail("Sequence \"%s\" is linked to table \"%s\".",
11777  NameStr(tuple_class->relname),
11778  get_rel_name(tableId))));
11779  }
11780  break;
11781  case RELKIND_COMPOSITE_TYPE:
11782  if (recursing)
11783  break;
11784  ereport(ERROR,
11785  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11786  errmsg("\"%s\" is a composite type",
11787  NameStr(tuple_class->relname)),
11788  errhint("Use ALTER TYPE instead.")));
11789  break;
11790  case RELKIND_TOASTVALUE:
11791  if (recursing)
11792  break;
11793  /* FALL THRU */
11794  default:
11795  ereport(ERROR,
11796  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11797  errmsg("\"%s\" is not a table, view, sequence, or foreign table",
11798  NameStr(tuple_class->relname))));
11799  }
11800 
11801  /*
11802  * If the new owner is the same as the existing owner, consider the
11803  * command to have succeeded. This is for dump restoration purposes.
11804  */
11805  if (tuple_class->relowner != newOwnerId)
11806  {
11807  Datum repl_val[Natts_pg_class];
11808  bool repl_null[Natts_pg_class];
11809  bool repl_repl[Natts_pg_class];
11810  Acl *newAcl;
11811  Datum aclDatum;
11812  bool isNull;
11813  HeapTuple newtuple;
11814 
11815  /* skip permission checks when recursing to index or toast table */
11816  if (!recursing)
11817  {
11818  /* Superusers can always do it */
11819  if (!superuser())
11820  {
11821  Oid namespaceOid = tuple_class->relnamespace;
11822  AclResult aclresult;
11823 
11824  /* Otherwise, must be owner of the existing object */
11825  if (!pg_class_ownercheck(relationOid, GetUserId()))
11827  RelationGetRelationName(target_rel));
11828 
11829  /* Must be able to become new owner */
11830  check_is_member_of_role(GetUserId(), newOwnerId);
11831 
11832  /* New owner must have CREATE privilege on namespace */
11833  aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
11834  ACL_CREATE);
11835  if (aclresult != ACLCHECK_OK)
11836  aclcheck_error(aclresult, OBJECT_SCHEMA,
11837  get_namespace_name(namespaceOid));
11838  }
11839  }
11840 
11841  memset(repl_null, false, sizeof(repl_null));
11842  memset(repl_repl, false, sizeof(repl_repl));
11843 
11844  repl_repl[Anum_pg_class_relowner - 1] = true;
11845  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
11846 
11847  /*
11848  * Determine the modified ACL for the new owner. This is only
11849  * necessary when the ACL is non-null.
11850  */
11851  aclDatum = SysCacheGetAttr(RELOID, tuple,
11852  Anum_pg_class_relacl,
11853  &isNull);
11854  if (!isNull)
11855  {
11856  newAcl = aclnewowner(DatumGetAclP(aclDatum),
11857  tuple_class->relowner, newOwnerId);
11858  repl_repl[Anum_pg_class_relacl - 1] = true;
11859  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
11860  }
11861 
11862  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
11863 
11864  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
11865 
11866  heap_freetuple(newtuple);
11867 
11868  /*
11869  * We must similarly update any per-column ACLs to reflect the new
11870  * owner; for neatness reasons that's split out as a subroutine.
11871  */
11872  change_owner_fix_column_acls(relationOid,
11873  tuple_class->relowner,
11874  newOwnerId);
11875 
11876  /*
11877  * Update owner dependency reference, if any. A composite type has
11878  * none, because it's tracked for the pg_type entry instead of here;
11879  * indexes and TOAST tables don't have their own entries either.
11880  */
11881  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
11882  tuple_class->relkind != RELKIND_INDEX &&
11883  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
11884  tuple_class->relkind != RELKIND_TOASTVALUE)
11885  changeDependencyOnOwner(RelationRelationId, relationOid,
11886  newOwnerId);
11887 
11888  /*
11889  * Also change the ownership of the table's row type, if it has one
11890  */
11891  if (tuple_class->relkind != RELKIND_INDEX &&
11892  tuple_class->relkind != RELKIND_PARTITIONED_INDEX)
11893  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
11894 
11895  /*
11896  * If we are operating on a table or materialized view, also change
11897  * the ownership of any indexes and sequences that belong to the
11898  * relation, as well as its toast table (if it has one).
11899  */
11900  if (tuple_class->relkind == RELKIND_RELATION ||
11901  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
11902  tuple_class->relkind == RELKIND_MATVIEW ||
11903  tuple_class->relkind == RELKIND_TOASTVALUE)
11904  {
11905  List *index_oid_list;
11906  ListCell *i;
11907 
11908  /* Find all the indexes belonging to this relation */
11909  index_oid_list = RelationGetIndexList(target_rel);
11910 
11911  /* For each index, recursively change its ownership */
11912  foreach(i, index_oid_list)
11913  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
11914 
11915  list_free(index_oid_list);
11916  }
11917 
11918  /* If it has a toast table, recurse to change its ownership */
11919  if (tuple_class->reltoastrelid != InvalidOid)
11920  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
11921  true, lockmode);
11922 
11923  /* If it has dependent sequences, recurse to change them too */
11924  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
11925  }
11926 
11927  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
11928 
11929  ReleaseSysCache(tuple);
11930  table_close(class_rel, RowExclusiveLock);
11931  relation_close(target_rel, NoLock);
11932 }
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:448
Oid GetUserId(void)
Definition: miscinit.c:380
#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:347
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:456
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:11702
#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:12006
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4347
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:11941
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:616
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 5535 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().

5536 {
5537  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
5538  bool typeOk = false;
5539 
5540  if (typ->typtype == TYPTYPE_COMPOSITE)
5541  {
5542  Relation typeRelation;
5543 
5544  Assert(OidIsValid(typ->typrelid));
5545  typeRelation = relation_open(typ->typrelid, AccessShareLock);
5546  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
5547 
5548  /*
5549  * Close the parent rel, but keep our AccessShareLock on it until xact
5550  * commit. That will prevent someone else from deleting or ALTERing
5551  * the type before the typed table creation/conversion commits.
5552  */
5553  relation_close(typeRelation, NoLock);
5554  }
5555  if (!typeOk)
5556  ereport(ERROR,
5557  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5558  errmsg("type %s is not a composite type",
5559  format_type_be(typ->oid))));
5560 }
#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:83
#define OidIsValid(objectId)
Definition: c.h:645
#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:739
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 3423 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().

3424 {
3425  int expected_refcnt;
3426 
3427  expected_refcnt = rel->rd_isnailed ? 2 : 1;
3428  if (rel->rd_refcnt != expected_refcnt)
3429  ereport(ERROR,
3430  (errcode(ERRCODE_OBJECT_IN_USE),
3431  /* translator: first %s is a SQL command, eg ALTER TABLE */
3432  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
3433  stmt, RelationGetRelationName(rel))));
3434 
3435  if (rel->rd_rel->relkind != RELKIND_INDEX &&
3436  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
3438  ereport(ERROR,
3439  (errcode(ERRCODE_OBJECT_IN_USE),
3440  /* translator: first %s is a SQL command, eg ALTER TABLE */
3441  errmsg("cannot %s \"%s\" because it has pending trigger events",
3442  stmt, RelationGetRelationName(rel))));
3443 }
bool rd_isnailed
Definition: rel.h:60
int errcode(int sqlerrcode)
Definition: elog.c:608
Form_pg_class rd_rel
Definition: rel.h:83
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:456
#define ereport(elevel, rest)
Definition: elog.h:141
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5637
int errmsg(const char *fmt,...)
Definition: elog.c:822
int rd_refcnt
Definition: rel.h:57
#define RelationGetRelid(relation)
Definition: rel.h:422

◆ DefineRelation()

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

Definition at line 554 of file tablecmds.c.

References AccessExclusiveLock, CreateStmt::accessMethod, AccessShareLock, ACL_CREATE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, addRangeTableEntryForRelation(), AddRelationNewConstraints(), addRTEtoQuery(), allowSystemTableMods, Assert, RawColumnDefault::attnum, CookedConstraint::attnum, attnum, BuildDescForRelation(), check_default_partition_contents(), check_new_partition_bound(), CloneForeignKeyConstraints(), CloneRowTriggersToPartition(), CommandCounterIncrement(), ComputePartitionAttrs(), CookedConstraint::conoid, CONSTR_DEFAULT, CreateStmt::constraints, CookedConstraint::contype, convert_tuples_by_name_map(), 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().

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

◆ ExecuteTruncate()

void ExecuteTruncate ( TruncateStmt stmt)

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

1504 {
1505  List *rels = NIL;
1506  List *relids = NIL;
1507  List *relids_logged = NIL;
1508  ListCell *cell;
1509 
1510  /*
1511  * Open, exclusive-lock, and check all the explicitly-specified relations
1512  */
1513  foreach(cell, stmt->relations)
1514  {
1515  RangeVar *rv = lfirst(cell);
1516  Relation rel;
1517  bool recurse = rv->inh;
1518  Oid myrelid;
1519  LOCKMODE lockmode = AccessExclusiveLock;
1520 
1521  myrelid = RangeVarGetRelidExtended(rv, lockmode,
1523  NULL);
1524 
1525  /* open the relation, we already hold a lock on it */
1526  rel = table_open(myrelid, NoLock);
1527 
1528  /* don't throw error for "TRUNCATE foo, foo" */
1529  if (list_member_oid(relids, myrelid))
1530  {
1531  table_close(rel, lockmode);
1532  continue;
1533  }
1534 
1535  /*
1536  * RangeVarGetRelidExtended() has done most checks with its callback,
1537  * but other checks with the now-opened Relation remain.
1538  */
1540 
1541  rels = lappend(rels, rel);
1542  relids = lappend_oid(relids, myrelid);
1543  /* Log this relation only if needed for logical decoding */
1544  if (RelationIsLogicallyLogged(rel))
1545  relids_logged = lappend_oid(relids_logged, myrelid);
1546 
1547  if (recurse)
1548  {
1549  ListCell *child;
1550  List *children;
1551 
1552  children = find_all_inheritors(myrelid, lockmode, NULL);
1553 
1554  foreach(child, children)
1555  {
1556  Oid childrelid = lfirst_oid(child);
1557 
1558  if (list_member_oid(relids, childrelid))
1559  continue;
1560 
1561  /* find_all_inheritors already got lock */
1562  rel = table_open(childrelid, NoLock);
1563 
1564  /*
1565  * It is possible that the parent table has children that are
1566  * temp tables of other backends. We cannot safely access
1567  * such tables (because of buffering issues), and the best
1568  * thing to do is to silently ignore them. Note that this
1569  * check is the same as one of the checks done in
1570  * truncate_check_activity() called below, still it is kept
1571  * here for simplicity.
1572  */
1573  if (RELATION_IS_OTHER_TEMP(rel))
1574  {
1575  table_close(rel, lockmode);
1576  continue;
1577  }
1578 
1581 
1582  rels = lappend(rels, rel);
1583  relids = lappend_oid(relids, childrelid);
1584  /* Log this relation only if needed for logical decoding */
1585  if (RelationIsLogicallyLogged(rel))
1586  relids_logged = lappend_oid(relids_logged, childrelid);
1587  }
1588  }
1589  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1590  ereport(ERROR,
1591  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1592  errmsg("cannot truncate only a partitioned table"),
1593  errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1594  }
1595 
1596  ExecuteTruncateGuts(rels, relids, relids_logged,
1597  stmt->behavior, stmt->restart_seqs);
1598 
1599  /* And close the rels */
1600  foreach(cell, rels)
1601  {
1602  Relation rel = (Relation) lfirst(cell);
1603 
1604  table_close(rel, NoLock);
1605  }
1606 }
#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:14817
int errcode(int sqlerrcode)
Definition: elog.c:608
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:594
Form_pg_class rd_rel
Definition: rel.h:83
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
DropBehavior behavior
Definition: parsenodes.h:2647
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:1622
List * relations
Definition: parsenodes.h:2645
#define NoLock
Definition: lockdefs.h:34
bool restart_seqs
Definition: parsenodes.h:2646
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:1950
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:552
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:1913
#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:422
#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 1622 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_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().

1624 {
1625  List *rels;
1626  List *seq_relids = NIL;
1627  EState *estate;
1628  ResultRelInfo *resultRelInfos;
1629  ResultRelInfo *resultRelInfo;
1630  SubTransactionId mySubid;
1631  ListCell *cell;
1632  Oid *logrelids;
1633 
1634  /*
1635  * Check the explicitly-specified relations.
1636  *
1637  * In CASCADE mode, suck in all referencing relations as well. This
1638  * requires multiple iterations to find indirectly-dependent relations. At
1639  * each phase, we need to exclusive-lock new rels before looking for their
1640  * dependencies, else we might miss something. Also, we check each rel as
1641  * soon as we open it, to avoid a faux pas such as holding lock for a long
1642  * time on a rel we have no permissions for.
1643  */
1644  rels = list_copy(explicit_rels);
1645  if (behavior == DROP_CASCADE)
1646  {
1647  for (;;)
1648  {
1649  List *newrelids;
1650 
1651  newrelids = heap_truncate_find_FKs(relids);
1652  if (newrelids == NIL)
1653  break; /* nothing else to add */
1654 
1655  foreach(cell, newrelids)
1656  {
1657  Oid relid = lfirst_oid(cell);
1658  Relation rel;
1659 
1660  rel = table_open(relid, AccessExclusiveLock);
1661  ereport(NOTICE,
1662  (errmsg("truncate cascades to table \"%s\"",
1663  RelationGetRelationName(rel))));
1664  truncate_check_rel(relid, rel->rd_rel);
1666  rels = lappend(rels, rel);
1667  relids = lappend_oid(relids, relid);
1668  /* Log this relation only if needed for logical decoding */
1669  if (RelationIsLogicallyLogged(rel))
1670  relids_logged = lappend_oid(relids_logged, relid);
1671  }
1672  }
1673  }
1674 
1675  /*
1676  * Check foreign key references. In CASCADE mode, this should be
1677  * unnecessary since we just pulled in all the references; but as a
1678  * cross-check, do it anyway if in an Assert-enabled build.
1679  */
1680 #ifdef USE_ASSERT_CHECKING
1681  heap_truncate_check_FKs(rels, false);
1682 #else
1683  if (behavior == DROP_RESTRICT)
1684  heap_truncate_check_FKs(rels, false);
1685 #endif
1686 
1687  /*
1688  * If we are asked to restart sequences, find all the sequences, lock them
1689  * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1690  * We want to do this early since it's pointless to do all the truncation
1691  * work only to fail on sequence permissions.
1692  */
1693  if (restart_seqs)
1694  {
1695  foreach(cell, rels)
1696  {
1697  Relation rel = (Relation) lfirst(cell);
1698  List *seqlist = getOwnedSequences(RelationGetRelid(rel));
1699  ListCell *seqcell;
1700 
1701  foreach(seqcell, seqlist)
1702  {
1703  Oid seq_relid = lfirst_oid(seqcell);
1704  Relation seq_rel;
1705 
1706  seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1707 
1708  /* This check must match AlterSequence! */
1709  if (!pg_class_ownercheck(seq_relid, GetUserId()))
1711  RelationGetRelationName(seq_rel));
1712 
1713  seq_relids = lappend_oid(seq_relids, seq_relid);
1714 
1715  relation_close(seq_rel, NoLock);
1716  }
1717  }
1718  }
1719 
1720  /* Prepare to catch AFTER triggers. */
1722 
1723  /*
1724  * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1725  * each relation. We don't need to call ExecOpenIndices, though.
1726  */
1727  estate = CreateExecutorState();
1728  resultRelInfos = (ResultRelInfo *)
1729  palloc(list_length(rels) * sizeof(ResultRelInfo));
1730  resultRelInfo = resultRelInfos;
1731  foreach(cell, rels)
1732  {
1733  Relation rel = (Relation) lfirst(cell);
1734 
1735  InitResultRelInfo(resultRelInfo,
1736  rel,
1737  0, /* dummy rangetable index */
1738  NULL,
1739  0);
1740  resultRelInfo++;
1741  }
1742  estate->es_result_relations = resultRelInfos;
1743  estate->es_num_result_relations = list_length(rels);
1744 
1745  /*
1746  * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
1747  * truncating (this is because one of them might throw an error). Also, if
1748  * we were to allow them to prevent statement execution, that would need
1749  * to be handled here.
1750  */
1751  resultRelInfo = resultRelInfos;
1752  foreach(cell, rels)
1753  {
1754  estate->es_result_relation_info = resultRelInfo;
1755  ExecBSTruncateTriggers(estate, resultRelInfo);
1756  resultRelInfo++;
1757  }
1758 
1759  /*
1760  * OK, truncate each table.
1761  */
1762  mySubid = GetCurrentSubTransactionId();
1763 
1764  foreach(cell, rels)
1765  {
1766  Relation rel = (Relation) lfirst(cell);
1767 
1768  /* Skip partitioned tables as there is nothing to do */
1769  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1770  continue;
1771 
1772  /*
1773  * Normally, we need a transaction-safe truncation here. However, if
1774  * the table was either created in the current (sub)transaction or has
1775  * a new relfilenode in the current (sub)transaction, then we can just
1776  * truncate it in-place, because a rollback would cause the whole
1777  * table or the current physical file to be thrown away anyway.
1778  */
1779  if (rel->rd_createSubid == mySubid ||
1780  rel->rd_newRelfilenodeSubid == mySubid)
1781  {
1782  /* Immediate, non-rollbackable truncation is OK */
1783  heap_truncate_one_rel(rel);
1784  }
1785  else
1786  {
1787  Oid heap_relid;
1788  Oid toast_relid;
1789 
1790  /*
1791  * This effectively deletes all rows in the table, and may be done
1792  * in a serializable transaction. In that case we must record a
1793  * rw-conflict in to this transaction from each transaction
1794  * holding a predicate lock on the table.
1795  */
1797 
1798  /*
1799  * Need the full transaction-safe pushups.
1800  *
1801  * Create a new empty storage file for the relation, and assign it
1802  * as the relfilenode value. The old storage file is scheduled for
1803  * deletion at commit.
1804  */
1805  RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence);
1806 
1807  heap_relid = RelationGetRelid(rel);
1808 
1809  /*
1810  * The same for the toast table, if any.
1811  */
1812  toast_relid = rel->rd_rel->reltoastrelid;
1813  if (OidIsValid(toast_relid))
1814  {
1815  Relation toastrel = relation_open(toast_relid,
1817 
1818  RelationSetNewRelfilenode(toastrel,
1819  toastrel->rd_rel->relpersistence);
1820  table_close(toastrel, NoLock);
1821  }
1822 
1823  /*
1824  * Reconstruct the indexes to match, and we're done.
1825  */
1827  }
1828 
1829  pgstat_count_truncate(rel);
1830  }
1831 
1832  /*
1833  * Restart owned sequences if we were asked to.
1834  */
1835  foreach(cell, seq_relids)
1836  {
1837  Oid seq_relid = lfirst_oid(cell);
1838 
1839  ResetSequence(seq_relid);
1840  }
1841 
1842  /*
1843  * Write a WAL record to allow this set of actions to be logically
1844  * decoded.
1845  *
1846  * Assemble an array of relids so we can write a single WAL record for the
1847  * whole action.
1848  */
1849  if (list_length(relids_logged) > 0)
1850  {
1851  xl_heap_truncate xlrec;
1852  int i = 0;
1853 
1854  /* should only get here if wal_level >= logical */
1856 
1857  logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
1858  foreach(cell, relids_logged)
1859  logrelids[i++] = lfirst_oid(cell);
1860 
1861  xlrec.dbId = MyDatabaseId;
1862  xlrec.nrelids = list_length(relids_logged);
1863  xlrec.flags = 0;
1864  if (behavior == DROP_CASCADE)
1865  xlrec.flags |= XLH_TRUNCATE_CASCADE;
1866  if (restart_seqs)
1868 
1869  XLogBeginInsert();
1870  XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
1871  XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
1872 
1874 
1875  (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
1876  }
1877 
1878  /*
1879  * Process all AFTER STATEMENT TRUNCATE triggers.
1880  */
1881  resultRelInfo = resultRelInfos;
1882  foreach(cell, rels)
1883  {
1884  estate->es_result_relation_info = resultRelInfo;
1885  ExecASTruncateTriggers(estate, resultRelInfo);
1886  resultRelInfo++;
1887  }
1888 
1889  /* Handle queued AFTER triggers */
1890  AfterTriggerEndQuery(estate);
1891 
1892  /* We can clean up the EState now */
1893  FreeExecutorState(estate);
1894 
1895  /*
1896  * Close any rels opened by CASCADE (can't do this while EState still
1897  * holds refs)
1898  */
1899  rels = list_difference_ptr(rels, explicit_rels);
1900  foreach(cell, rels)
1901  {
1902  Relation rel = (Relation) lfirst(cell);
1903 
1904  table_close(rel, NoLock);
1905  }
1906 }
#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:380
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3226
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:3270
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:80
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:228
uint32 SubTransactionId
Definition: c.h:518
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:594
Form_pg_class rd_rel
Definition: rel.h:83
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:645
void RelationSetNewRelfilenode(Relation relation, char persistence)
Definition: relcache.c:3417
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:3244
#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:519
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3297
#define RelationGetRelationName(relation)
Definition: rel.h:456
void pgstat_count_truncate(Relation rel)
Definition: pgstat.c:2047
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:79
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:520
#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:1950
#define NOTICE
Definition: elog.h:37
void AfterTriggerBeginQuery(void)
Definition: trigger.c:4782
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:739
#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:4510
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:1913
#define AccessExclusiveLock
Definition: lockdefs.h:45
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:4802
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:3638
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:422
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3365
#define lfirst_oid(lc)
Definition: pg_list.h:192
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:521

◆ find_composite_type_dependencies()

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

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

5370 {
5371  Relation depRel;
5372  ScanKeyData key[2];
5373  SysScanDesc depScan;
5374  HeapTuple depTup;
5375 
5376  /* since this function recurses, it could be driven to stack overflow */
5378 
5379  /*
5380  * We scan pg_depend to find those things that depend on the given type.
5381  * (We assume we can ignore refobjsubid for a type.)
5382  */
5383  depRel = table_open(DependRelationId, AccessShareLock);
5384 
5385  ScanKeyInit(&key[0],
5386  Anum_pg_depend_refclassid,
5387  BTEqualStrategyNumber, F_OIDEQ,
5388  ObjectIdGetDatum(TypeRelationId));
5389  ScanKeyInit(&key[1],
5390  Anum_pg_depend_refobjid,
5391  BTEqualStrategyNumber, F_OIDEQ,
5392  ObjectIdGetDatum(typeOid));
5393 
5394  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
5395  NULL, 2, key);
5396 
5397  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
5398  {
5399  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
5400  Relation rel;
5401  Form_pg_attribute att;
5402 
5403  /* Check for directly dependent types */
5404  if (pg_depend->classid == TypeRelationId)
5405  {
5406  /*
5407  * This must be an array, domain, or range containing the given
5408  * type, so recursively check for uses of this type. Note that
5409  * any error message will mention the original type not the
5410  * container; this is intentional.
5411  */
5412  find_composite_type_dependencies(pg_depend->objid,
5413  origRelation, origTypeName);
5414  continue;
5415  }
5416 
5417  /* Else, ignore dependees that aren't user columns of relations */
5418  /* (we assume system columns are never of interesting types) */
5419  if (pg_depend->classid != RelationRelationId ||
5420  pg_depend->objsubid <= 0)
5421  continue;
5422 
5423  rel = relation_open(pg_depend->objid, AccessShareLock);
5424  att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
5425 
5426  if (rel->rd_rel->relkind == RELKIND_RELATION ||
5427  rel->rd_rel->relkind == RELKIND_MATVIEW ||
5428  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5429  {
5430  if (origTypeName)
5431  ereport(ERROR,
5432  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5433  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5434  origTypeName,
5436  NameStr(att->attname))));
5437  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
5438  ereport(ERROR,
5439  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5440  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5441  RelationGetRelationName(origRelation),
5443  NameStr(att->attname))));
5444  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
5445  ereport(ERROR,
5446  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5447  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
5448  RelationGetRelationName(origRelation),
5450  NameStr(att->attname))));
5451  else
5452  ereport(ERROR,
5453  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5454  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
5455  RelationGetRelationName(origRelation),
5457  NameStr(att->attname))));
5458  }
5459  else if (OidIsValid(rel->rd_rel->reltype))
5460  {
5461  /*
5462  * A view or composite type itself isn't a problem, but we must
5463  * recursively check for indirect dependencies via its rowtype.
5464  */
5466  origRelation, origTypeName);
5467  }
5468 
5470  }
5471 
5472  systable_endscan(depScan);
5473 
5475 }
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:5368
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:608
Form_pg_class rd_rel
Definition: rel.h:83
#define OidIsValid(objectId)
Definition: c.h:645
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:3284
#define RelationGetRelationName(relation)
Definition: rel.h:456
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:84
#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:616
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 15318 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().

15320 {
15321  List *existConstraint = NIL;
15322  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
15323  int i;
15324 
15325  if (constr && constr->has_not_null)
15326  {
15327  int natts = scanrel->rd_att->natts;
15328 
15329  for (i = 1; i <= natts; i++)
15330  {
15331  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
15332 
15333  if (att->attnotnull && !att->attisdropped)
15334  {
15335  NullTest *ntest = makeNode(NullTest);
15336 
15337  ntest->arg = (Expr *) makeVar(1,
15338  i,
15339  att->atttypid,
15340  att->atttypmod,
15341  att->attcollation,
15342  0);
15343  ntest->nulltesttype = IS_NOT_NULL;
15344 
15345  /*
15346  * argisrow=false is correct even for a composite column,
15347  * because attnotnull does not represent a SQL-spec IS NOT
15348  * NULL test in such a case, just IS DISTINCT FROM NULL.
15349  */
15350  ntest->argisrow = false;
15351  ntest->location = -1;
15352  existConstraint = lappend(existConstraint, ntest);
15353  }
15354  }
15355  }
15356 
15357  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
15358 }
#define NIL
Definition: pg_list.h:65
#define RelationGetDescr(relation)
Definition: rel.h:448
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Expr * arg
Definition: primnodes.h:1205
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:84
NullTestType nulltesttype
Definition: primnodes.h:1206
#define makeNode(_type_)
Definition: nodes.h:573
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:15371
int location
Definition: primnodes.h:1208
int i
bool argisrow
Definition: primnodes.h:1207
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 14618 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().

14619 {
14620  ListCell *l;
14621  List *oids_to_truncate = NIL;
14622  List *oids_to_drop = NIL;
14623 
14624  foreach(l, on_commits)
14625  {
14626  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
14627 
14628  /* Ignore entry if already dropped in this xact */
14630  continue;
14631 
14632  switch (oc->oncommit)
14633  {
14634  case ONCOMMIT_NOOP:
14636  /* Do nothing (there shouldn't be such entries, actually) */
14637  break;
14638  case ONCOMMIT_DELETE_ROWS:
14639 
14640  /*
14641  * If this transaction hasn't accessed any temporary
14642  * relations, we can skip truncating ON COMMIT DELETE ROWS
14643  * tables, as they must still be empty.
14644  */
14646  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
14647  break;
14648  case ONCOMMIT_DROP:
14649  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
14650  break;
14651  }
14652  }
14653 
14654  /*
14655  * Truncate relations before dropping so that all dependencies between
14656  * relations are removed after they are worked on. Doing it like this
14657  * might be a waste as it is possible that a relation being truncated will
14658  * be dropped anyway due to its parent being dropped, but this makes the
14659  * code more robust because of not having to re-check that the relation
14660  * exists at truncation time.
14661  */
14662  if (oids_to_truncate != NIL)
14663  heap_truncate(oids_to_truncate);
14664 
14665  if (oids_to_drop != NIL)
14666  {
14667  ObjectAddresses *targetObjects = new_object_addresses();
14668  ListCell *l;
14669 
14670  foreach(l, oids_to_drop)
14671  {
14672  ObjectAddress object;
14673 
14674  object.classId = RelationRelationId;
14675  object.objectId = lfirst_oid(l);
14676  object.objectSubId = 0;
14677 
14678  Assert(!object_address_present(&object, targetObjects));
14679 
14680  add_exact_object_address(&object, targetObjects);
14681  }
14682 
14683  /*
14684  * Since this is an automatic drop, rather than one directly initiated
14685  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
14686  */
14687  performMultipleDeletions(targetObjects, DROP_CASCADE,
14689 
14690 #ifdef USE_ASSERT_CHECKING
14691 
14692  /*
14693  * Note that table deletion will call remove_on_commit_action, so the
14694  * entry should get marked as deleted.
14695  */
14696  foreach(l, on_commits)
14697  {
14698  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
14699 
14700  if (oc->oncommit != ONCOMMIT_DROP)
14701  continue;
14702 
14704  }
14705 #endif
14706  }
14707 }
#define NIL
Definition: pg_list.h:65
OnCommitAction oncommit
Definition: tablecmds.c:108
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2517
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2457
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2402
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
static List * on_commits
Definition: tablecmds.c:121
int MyXactFlags
Definition: xact.c:118
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:97
SubTransactionId deleting_subid
Definition: tablecmds.c:118
#define Assert(condition)
Definition: c.h:739
#define lfirst(lc)
Definition: pg_list.h:190
#define PERFORM_DELETION_QUIETLY
Definition: dependency.h:136
void heap_truncate(List *relids)
Definition: heap.c:3185
#define InvalidSubTransactionId
Definition: c.h:520
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 14840 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().

14842 {
14843  HeapTuple tuple;
14844 
14845  /* Nothing to do if the relation was not found. */
14846  if (!OidIsValid(relId))
14847  return;
14848 
14849  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
14850  if (!HeapTupleIsValid(tuple)) /* should not happen */
14851  elog(ERROR, "cache lookup failed for relation %u", relId);
14852 
14853  if (!pg_class_ownercheck(relId, GetUserId()))
14855  relation->relname);
14856 
14857  if (!allowSystemTableMods &&
14858  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
14859  ereport(ERROR,
14860  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
14861  errmsg("permission denied: \"%s\" is a system catalog",
14862  relation->relname)));
14863 
14864  ReleaseSysCache(tuple);
14865 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Oid GetUserId(void)
Definition: miscinit.c:380
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
int errcode(int sqlerrcode)
Definition: elog.c:608
#define OidIsValid(objectId)
Definition: c.h:645
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:81
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:150
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 14785 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(), relkind, and RangeVar::relname.

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

14787 {
14788  char relkind;
14789 
14790  /* Nothing to do if the relation was not found. */
14791  if (!OidIsValid(relId))
14792  return;
14793 
14794  /*
14795  * If the relation does exist, check whether it's an index. But note that
14796  * the relation might have been dropped between the time we did the name
14797  * lookup and now. In that case, there's nothing to do.
14798  */
14799  relkind = get_rel_relkind(relId);
14800  if (!relkind)
14801  return;
14802  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
14803  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
14804  ereport(ERROR,
14805  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14806  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
14807 
14808  /* Check permissions */
14809  if (!pg_class_ownercheck(relId, GetUserId()))
14811 }
Oid GetUserId(void)
Definition: miscinit.c:380
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
int errcode(int sqlerrcode)
Definition: elog.c:608
#define OidIsValid(objectId)
Definition: c.h:645
char relkind
Definition: pg_class.h:81
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 14559 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().

14560 {
14561  OnCommitItem *oc;
14562  MemoryContext oldcxt;
14563 
14564  /*
14565  * We needn't bother registering the relation unless there is an ON COMMIT
14566  * action we need to take.
14567  */
14569  return;
14570 
14572 
14573  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
14574  oc->relid = relid;
14575  oc->oncommit = action;
14578 
14579  /*
14580  * We use lcons() here so that ON COMMIT actions are processed in reverse
14581  * order of registration. That might not be essential but it seems
14582  * reasonable.
14583  */
14584  on_commits = lcons(oc, on_commits);
14585 
14586  MemoryContextSwitchTo(oldcxt);
14587 }
OnCommitAction oncommit
Definition: tablecmds.c:108
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
SubTransactionId creating_subid
Definition: tablecmds.c:117
static List * on_commits
Definition: tablecmds.c:121
SubTransactionId deleting_subid
Definition: tablecmds.c:118
List * lcons(void *datum, List *list)
Definition: list.c:454
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:707
#define InvalidSubTransactionId
Definition: c.h:520
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 14595 of file tablecmds.c.

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

Referenced by heap_drop_with_catalog().

14596 {
14597  ListCell *l;
14598 
14599  foreach(l, on_commits)
14600  {
14601  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
14602 
14603  if (oc->relid == relid)
14604  {
14606  break;
14607  }
14608  }
14609 }
static List * on_commits
Definition: tablecmds.c:121
SubTransactionId deleting_subid
Definition: tablecmds.c:118
#define lfirst(lc)
Definition: pg_list.h:190
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:707

◆ RemoveRelations()

void RemoveRelations ( DropStmt drop)

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

Referenced by ExecDropStmt().

1230 {
1231  ObjectAddresses *objects;
1232  char relkind;
1233  ListCell *cell;
1234  int flags = 0;
1235  LOCKMODE lockmode = AccessExclusiveLock;
1236 
1237  /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1238  if (drop->concurrent)
1239  {
1241  lockmode = ShareUpdateExclusiveLock;
1242  Assert(drop->removeType == OBJECT_INDEX);
1243  if (list_length(drop->objects) != 1)
1244  ereport(ERROR,
1245  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1246  errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1247  if (drop->behavior == DROP_CASCADE)
1248  ereport(ERROR,
1249  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1250  errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1251  }
1252 
1253  /*
1254  * First we identify all the relations, then we delete them in a single
1255  * performMultipleDeletions() call. This is to avoid unwanted DROP
1256  * RESTRICT errors if one of the relations depends on another.
1257  */
1258 
1259  /* Determine required relkind */
1260  switch (drop->removeType)
1261  {
1262  case OBJECT_TABLE:
1263  relkind = RELKIND_RELATION;
1264  break;
1265 
1266  case OBJECT_INDEX:
1267  relkind = RELKIND_INDEX;
1268  break;
1269 
1270  case OBJECT_SEQUENCE:
1271  relkind = RELKIND_SEQUENCE;
1272  break;
1273 
1274  case OBJECT_VIEW:
1275  relkind = RELKIND_VIEW;
1276  break;
1277 
1278  case OBJECT_MATVIEW:
1279  relkind = RELKIND_MATVIEW;
1280  break;
1281 
1282  case OBJECT_FOREIGN_TABLE:
1283  relkind = RELKIND_FOREIGN_TABLE;
1284  break;
1285 
1286  default:
1287  elog(ERROR, "unrecognized drop object type: %d",
1288  (int) drop->removeType);
1289  relkind = 0; /* keep compiler quiet */
1290  break;
1291  }
1292 
1293  /* Lock and validate each relation; build a list of object addresses */
1294  objects = new_object_addresses();
1295 
1296  foreach(cell, drop->objects)
1297  {
1298  RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1299  Oid relOid;
1300  ObjectAddress obj;
1302 
1303  /*
1304  * These next few steps are a great deal like relation_openrv, but we
1305  * don't bother building a relcache entry since we don't need it.
1306  *
1307  * Check for shared-cache-inval messages before trying to access the
1308  * relation. This is needed to cover the case where the name
1309  * identifies a rel that has been dropped and recreated since the
1310  * start of our transaction: if we don't flush the old syscache entry,
1311  * then we'll latch onto that entry and suffer an error later.
1312  */
1314 
1315  /* Look up the appropriate relation using namespace search. */
1316  state.relkind = relkind;
1317  state.heapOid = InvalidOid;
1318  state.partParentOid = InvalidOid;
1319  state.concurrent = drop->concurrent;
1320  relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1322  (void *) &state);
1323 
1324  /* Not there? */
1325  if (!OidIsValid(relOid))
1326  {
1327  DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1328  continue;
1329  }
1330 
1331  /* OK, we're ready to delete this one */
1332  obj.classId = RelationRelationId;
1333  obj.objectId = relOid;
1334  obj.objectSubId = 0;
1335 
1336  add_exact_object_address(&obj, objects);
1337  }
1338 
1339  performMultipleDeletions(objects, drop->behavior, flags);
1340 
1341  free_object_addresses(objects);
1342 }
void AcceptInvalidationMessages(void)
Definition: inval.c:681
int LOCKMODE
Definition: lockdefs.h:26
List * objects
Definition: parsenodes.h:2631
bool missing_ok
Definition: parsenodes.h:2634
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:2457
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2402
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2697
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
ObjectType removeType
Definition: parsenodes.h:2632
char relkind
Definition: pg_class.h:81
#define PERFORM_DELETION_CONCURRENTLY
Definition: dependency.h:135
#define ERROR
Definition: elog.h:43
bool concurrent
Definition: parsenodes.h:2635
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:228
DropBehavior behavior
Definition: parsenodes.h:2633
#define ereport(elevel, rest)
Definition: elog.h:141
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:1351
#define InvalidOid
Definition: postgres_ext.h:36
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define Assert(condition)
Definition: c.h:739
#define lfirst(lc)
Definition: pg_list.h:190
Definition: regguts.h:298
static int list_length(const List *l)
Definition: pg_list.h:169
#define AccessExclusiveLock
Definition: lockdefs.h:45
static void DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
Definition: tablecmds.c:1154
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 3086 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().

3087 {
3088  Oid relid;
3090  ObjectAddress address;
3091 
3092  /* lock level taken here should match renameatt_internal */
3094  stmt->missing_ok ? RVR_MISSING_OK : 0,
3096  NULL);
3097 
3098  if (!OidIsValid(relid))
3099  {
3100  ereport(NOTICE,
3101  (errmsg("relation \"%s\" does not exist, skipping",
3102  stmt->relation->relname)));
3103  return InvalidObjectAddress;
3104  }
3105 
3106  attnum =
3107  renameatt_internal(relid,
3108  stmt->subname, /* old att name */
3109  stmt->newname, /* new att name */
3110  stmt->relation->inh, /* recursive? */
3111  false, /* recursing? */
3112  0, /* expected inhcount */
3113  stmt->behavior);
3114 
3115  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3116 
3117  return address;
3118 }
char * subname
Definition: parsenodes.h:2895
char * newname
Definition: parsenodes.h:2897
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2899
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:2893
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:3066
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:2921
#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:2898
int16 AttrNumber
Definition: attnum.h:21

◆ RenameConstraint()

ObjectAddress RenameConstraint ( RenameStmt stmt)

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

3231 {
3232  Oid relid = InvalidOid;
3233  Oid typid = InvalidOid;
3234 
3235  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3236  {
3237  Relation rel;
3238  HeapTuple tup;
3239 
3241  rel = table_open(TypeRelationId, RowExclusiveLock);
3242  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3243  if (!HeapTupleIsValid(tup))
3244  elog(ERROR, "cache lookup failed for type %u", typid);
3245  checkDomainOwner(tup);
3246  ReleaseSysCache(tup);
3247  table_close(rel, NoLock);
3248  }
3249  else
3250  {
3251  /* lock level taken here should match rename_constraint_internal */
3253  stmt->missing_ok ? RVR_MISSING_OK : 0,
3255  NULL);
3256  if (!OidIsValid(relid))
3257  {
3258  ereport(NOTICE,
3259  (errmsg("relation \"%s\" does not exist, skipping",
3260  stmt->relation->relname)));
3261  return InvalidObjectAddress;
3262  }
3263  }
3264 
3265  return
3266  rename_constraint_internal(relid, typid,
3267  stmt->subname,
3268  stmt->newname,
3269  (stmt->relation &&
3270  stmt->relation->inh), /* recursive? */
3271  false, /* recursing? */
3272  0 /* expected inhcount */ );
3273 
3274 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
char * subname
Definition: parsenodes.h:2895
ObjectType renameType
Definition: parsenodes.h:2891
#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:3124
char * newname
Definition: parsenodes.h:2897
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2899
#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:2894
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:2893
#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:3066
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 3281 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().

3282 {
3283  bool is_index = stmt->renameType == OBJECT_INDEX;
3284  Oid relid;
3285  ObjectAddress address;
3286 
3287  /*
3288  * Grab an exclusive lock on the target table, index, sequence, view,
3289  * materialized view, or foreign table, which we will NOT release until
3290  * end of transaction.
3291  *
3292  * Lock level used here should match RenameRelationInternal, to avoid lock
3293  * escalation.
3294  */
3295  relid = RangeVarGetRelidExtended(stmt->relation,
3297  stmt->missing_ok ? RVR_MISSING_OK : 0,
3299  (void *) stmt);
3300 
3301  if (!OidIsValid(relid))
3302  {
3303  ereport(NOTICE,
3304  (errmsg("relation \"%s\" does not exist, skipping",
3305  stmt->relation->relname)));
3306  return InvalidObjectAddress;
3307  }
3308 
3309  /* Do the work */
3310  RenameRelationInternal(relid, stmt->newname, false, is_index);
3311 
3312  ObjectAddressSet(address, RelationRelationId, relid);
3313 
3314  return address;
3315 }
ObjectType renameType
Definition: parsenodes.h:2891
char * newname
Definition: parsenodes.h:2897
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2899
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:14872
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:2893
#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:3321

◆ RenameRelationInternal()

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

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

3322 {
3323  Relation targetrelation;
3324  Relation relrelation; /* for RELATION relation */
3325  HeapTuple reltup;
3326  Form_pg_class relform;
3327  Oid namespaceId;
3328 
3329  /*
3330  * Grab a lock on the target relation, which we will NOT release until end
3331  * of transaction. We need at least a self-exclusive lock so that
3332  * concurrent DDL doesn't overwrite the rename if they start updating
3333  * while still seeing the old version. The lock also guards against
3334  * triggering relcache reloads in concurrent sessions, which might not
3335  * handle this information changing under them. For indexes, we can use a
3336  * reduced lock level because RelationReloadIndexInfo() handles indexes
3337  * specially.
3338  */
3339  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
3340  namespaceId = RelationGetNamespace(targetrelation);
3341 
3342  /*
3343  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3344  */
3345  relrelation = table_open(RelationRelationId, RowExclusiveLock);
3346 
3347  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3348  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3349  elog(ERROR, "cache lookup failed for relation %u", myrelid);
3350  relform = (Form_pg_class) GETSTRUCT(reltup);
3351 
3352  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3353  ereport(ERROR,
3354  (errcode(ERRCODE_DUPLICATE_TABLE),
3355  errmsg("relation \"%s\" already exists",
3356  newrelname)));
3357 
3358  /*
3359  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
3360  * because it's a copy...)
3361  */
3362  namestrcpy(&(relform->relname), newrelname);
3363 
3364  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3365 
3366  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
3367  InvalidOid, is_internal);
3368 
3369  heap_freetuple(reltup);
3370  table_close(relrelation, RowExclusiveLock);
3371 
3372  /*
3373  * Also rename the associated type, if any.
3374  */
3375  if (OidIsValid(targetrelation->rd_rel->reltype))
3376  RenameTypeInternal(targetrelation->rd_rel->reltype,
3377  newrelname, namespaceId);
3378 
3379  /*
3380  * Also rename the associated constraint, if any.
3381  */
3382  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3383  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3384  {
3385  Oid constraintId = get_index_constraint(myrelid);
3386 
3387  if (OidIsValid(constraintId))
3388  RenameConstraintById(constraintId, newrelname);
3389  }
3390 
3391  /*
3392  * Close rel, but keep lock!
3393  */
3394  relation_close(targetrelation, NoLock);
3395 }
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:83
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:645
#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:150
#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:463

◆ SetRelationHasSubclass()

void SetRelationHasSubclass ( Oid  relationId,
bool  relhassubclass 
)

Definition at line 2839 of file tablecmds.c.

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

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

2840 {
2841  Relation relationRelation;
2842  HeapTuple tuple;
2843  Form_pg_class classtuple;
2844 
2845  /*
2846  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
2847  */
2848  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
2849  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
2850  if (!HeapTupleIsValid(tuple))
2851  elog(ERROR, "cache lookup failed for relation %u", relationId);
2852  classtuple = (Form_pg_class) GETSTRUCT(tuple);
2853 
2854  if (classtuple->relhassubclass != relhassubclass)
2855  {
2856  classtuple->relhassubclass = relhassubclass;
2857  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
2858  }
2859  else
2860  {
2861  /* no need to change tuple, but force relcache rebuild anyway */
2863  }
2864 
2865  heap_freetuple(tuple);
2866  table_close(relationRelation, RowExclusiveLock);
2867 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool relhassubclass
Definition: pg_class.h:102
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:150
#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