PostgreSQL Source Code git master
Loading...
Searching...
No Matches
tablecmds.h File Reference
#include "access/htup.h"
#include "catalog/dependency.h"
#include "catalog/objectaddress.h"
#include "nodes/parsenodes.h"
#include "storage/lockdefs.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.

Typedefs

typedef struct AlterTableUtilityContext AlterTableUtilityContext
 

Functions

ObjectAddress DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
 
TupleDesc BuildDescForRelation (const List *columns)
 
void RemoveRelations (DropStmt *drop)
 
Oid AlterTableLookupRelation (AlterTableStmt *stmt, LOCKMODE lockmode)
 
void AlterTable (AlterTableStmt *stmt, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
LOCKMODE AlterTableGetLockLevel (List *cmds)
 
void ATExecChangeOwner (Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
 
void AlterTableInternal (Oid relid, List *cmds, bool recurse)
 
Oid AlterTableMoveAll (AlterTableMoveAllStmt *stmt)
 
ObjectAddress AlterTableNamespace (AlterObjectSchemaStmt *stmt, Oid *oldschema)
 
void AlterTableNamespaceInternal (Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
 
void AlterRelationNamespaceInternal (Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
 
void CheckTableNotInUse (Relation rel, const char *stmt)
 
void ExecuteTruncate (TruncateStmt *stmt)
 
void ExecuteTruncateGuts (List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs, bool run_as_table_owner)
 
void SetRelationHasSubclass (Oid relationId, bool relhassubclass)
 
bool CheckRelationTableSpaceMove (Relation rel, Oid newTableSpaceId)
 
void SetRelationTableSpace (Relation rel, Oid newTableSpaceId, RelFileNumber newRelFilenumber)
 
ObjectAddress renameatt (RenameStmt *stmt)
 
ObjectAddress RenameConstraint (RenameStmt *stmt)
 
ObjectAddress RenameRelation (RenameStmt *stmt)
 
void RenameRelationInternal (Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
 
void ResetRelRewrite (Oid myrelid)
 
void find_composite_type_dependencies (Oid typeOid, Relation origRelation, const char *origTypeName)
 
void check_of_type (HeapTuple typetuple)
 
void register_on_commit_action (Oid relid, OnCommitAction action)
 
void remove_on_commit_action (Oid relid)
 
void PreCommit_on_commit_actions (void)
 
void AtEOXact_on_commit_actions (bool isCommit)
 
void AtEOSubXact_on_commit_actions (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
void RangeVarCallbackMaintainsTable (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)
 

Typedef Documentation

◆ AlterTableUtilityContext

Function Documentation

◆ AlterRelationNamespaceInternal()

void AlterRelationNamespaceInternal ( Relation  classRel,
Oid  relOid,
Oid  oldNspOid,
Oid  newNspOid,
bool  hasDependEntry,
ObjectAddresses objsMoved 
)
extern

Definition at line 19757 of file tablecmds.c.

19761{
19765 bool already_done = false;
19766
19767 /* no rel lock for relkind=c so use LOCKTAG_TUPLE */
19770 elog(ERROR, "cache lookup failed for relation %u", relOid);
19772
19773 Assert(classForm->relnamespace == oldNspOid);
19774
19775 thisobj.classId = RelationRelationId;
19776 thisobj.objectId = relOid;
19777 thisobj.objectSubId = 0;
19778
19779 /*
19780 * If the object has already been moved, don't move it again. If it's
19781 * already in the right place, don't move it, but still fire the object
19782 * access hook.
19783 */
19785 if (!already_done && oldNspOid != newNspOid)
19786 {
19787 ItemPointerData otid = classTup->t_self;
19788
19789 /* check for duplicate name (more friendly than unique-index failure) */
19790 if (get_relname_relid(NameStr(classForm->relname),
19792 ereport(ERROR,
19794 errmsg("relation \"%s\" already exists in schema \"%s\"",
19795 NameStr(classForm->relname),
19797
19798 /* classTup is a copy, so OK to scribble on */
19799 classForm->relnamespace = newNspOid;
19800
19803
19804
19805 /* Update dependency on schema if caller said so */
19806 if (hasDependEntry &&
19808 relOid,
19810 oldNspOid,
19811 newNspOid) != 1)
19812 elog(ERROR, "could not change schema dependency for relation \"%s\"",
19813 NameStr(classForm->relname));
19814 }
19815 else
19817 if (!already_done)
19818 {
19820
19822 }
19823
19825}
#define NameStr(name)
Definition c.h:894
#define Assert(condition)
Definition c.h:1002
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void UnlockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
Definition lmgr.c:601
#define InplaceUpdateTupleLock
Definition lockdefs.h:48
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3682
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition lsyscache.c:2199
static char * errmsg
#define InvokeObjectPostAlterHook(classId, objectId, subId)
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition pg_depend.c:470
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
#define InvalidOid
static int fb(int x)
HeapTuple SearchSysCacheLockedCopy1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:400

References add_exact_object_address(), Assert, CatalogTupleUpdate(), changeDependencyFor(), elog, ereport, errcode(), errmsg, ERROR, fb(), get_namespace_name(), get_relname_relid(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, InplaceUpdateTupleLock, InvalidOid, InvokeObjectPostAlterHook, NameStr, object_address_present(), ObjectIdGetDatum(), SearchSysCacheLockedCopy1(), and UnlockTuple().

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

◆ AlterTable()

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

Definition at line 4626 of file tablecmds.c.

4628{
4629 Relation rel;
4630
4631 /* Caller is required to provide an adequate lock. */
4632 rel = relation_open(context->relid, NoLock);
4633
4635
4636 ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4637}
#define stmt
#define NoLock
Definition lockdefs.h:34
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:48
static void CheckAlterTableIsSafe(Relation rel)
Definition tablecmds.c:4541
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition tablecmds.c:4967

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

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)
extern

Definition at line 4700 of file tablecmds.c.

4701{
4702 /*
4703 * This only works if we read catalog tables using MVCC snapshots.
4704 */
4705 ListCell *lcmd;
4707
4708 foreach(lcmd, cmds)
4709 {
4711 LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4712
4713 switch (cmd->subtype)
4714 {
4715 /*
4716 * These subcommands rewrite the heap, so require full locks.
4717 */
4718 case AT_AddColumn: /* may rewrite heap, in some cases and visible
4719 * to SELECT */
4720 case AT_SetAccessMethod: /* must rewrite heap */
4721 case AT_SetTableSpace: /* must rewrite heap */
4722 case AT_AlterColumnType: /* must rewrite heap */
4724 break;
4725
4726 /*
4727 * These subcommands may require addition of toast tables. If
4728 * we add a toast table to a table currently being scanned, we
4729 * might miss data added to the new toast table by concurrent
4730 * insert transactions.
4731 */
4732 case AT_SetStorage: /* may add toast tables, see
4733 * ATRewriteCatalogs() */
4735 break;
4736
4737 /*
4738 * Removing constraints can affect SELECTs that have been
4739 * optimized assuming the constraint holds true. See also
4740 * CloneFkReferenced.
4741 */
4742 case AT_DropConstraint: /* as DROP INDEX */
4743 case AT_DropNotNull: /* may change some SQL plans */
4745 break;
4746
4747 /*
4748 * Subcommands that may be visible to concurrent SELECTs
4749 */
4750 case AT_DropColumn: /* change visible to SELECT */
4751 case AT_AddColumnToView: /* CREATE VIEW */
4752 case AT_DropOids: /* used to equiv to DropColumn */
4753 case AT_EnableAlwaysRule: /* may change SELECT rules */
4754 case AT_EnableReplicaRule: /* may change SELECT rules */
4755 case AT_EnableRule: /* may change SELECT rules */
4756 case AT_DisableRule: /* may change SELECT rules */
4758 break;
4759
4760 /*
4761 * Changing owner may remove implicit SELECT privileges
4762 */
4763 case AT_ChangeOwner: /* change visible to SELECT */
4765 break;
4766
4767 /*
4768 * Changing foreign table options may affect optimization.
4769 */
4770 case AT_GenericOptions:
4773 break;
4774
4775 /*
4776 * These subcommands affect write operations only.
4777 */
4778 case AT_EnableTrig:
4781 case AT_EnableTrigAll:
4782 case AT_EnableTrigUser:
4783 case AT_DisableTrig:
4784 case AT_DisableTrigAll:
4785 case AT_DisableTrigUser:
4787 break;
4788
4789 /*
4790 * These subcommands affect write operations only. XXX
4791 * Theoretically, these could be ShareRowExclusiveLock.
4792 */
4793 case AT_ColumnDefault:
4795 case AT_AlterConstraint:
4796 case AT_AddIndex: /* from ADD CONSTRAINT */
4798 case AT_ReplicaIdentity:
4799 case AT_SetNotNull:
4804 case AT_AddIdentity:
4805 case AT_DropIdentity:
4806 case AT_SetIdentity:
4807 case AT_SetExpression:
4808 case AT_DropExpression:
4809 case AT_SetCompression:
4811 break;
4812
4813 case AT_AddConstraint:
4814 case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4815 case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4816 if (IsA(cmd->def, Constraint))
4817 {
4818 Constraint *con = (Constraint *) cmd->def;
4819
4820 switch (con->contype)
4821 {
4822 case CONSTR_EXCLUSION:
4823 case CONSTR_PRIMARY:
4824 case CONSTR_UNIQUE:
4825
4826 /*
4827 * Cases essentially the same as CREATE INDEX. We
4828 * could reduce the lock strength to ShareLock if
4829 * we can work out how to allow concurrent catalog
4830 * updates. XXX Might be set down to
4831 * ShareRowExclusiveLock but requires further
4832 * analysis.
4833 */
4835 break;
4836 case CONSTR_FOREIGN:
4837
4838 /*
4839 * We add triggers to both tables when we add a
4840 * Foreign Key, so the lock level must be at least
4841 * as strong as CREATE TRIGGER.
4842 */
4844 break;
4845
4846 default:
4848 }
4849 }
4850 break;
4851
4852 /*
4853 * These subcommands affect inheritance behaviour. Queries
4854 * started before us will continue to see the old inheritance
4855 * behaviour, while queries started after we commit will see
4856 * new behaviour. No need to prevent reads or writes to the
4857 * subtable while we hook it up though. Changing the TupDesc
4858 * may be a problem, so keep highest lock.
4859 */
4860 case AT_AddInherit:
4861 case AT_DropInherit:
4863 break;
4864
4865 /*
4866 * These subcommands affect implicit row type conversion. They
4867 * have affects similar to CREATE/DROP CAST on queries. don't
4868 * provide for invalidating parse trees as a result of such
4869 * changes, so we keep these at AccessExclusiveLock.
4870 */
4871 case AT_AddOf:
4872 case AT_DropOf:
4874 break;
4875
4876 /*
4877 * Only used by CREATE OR REPLACE VIEW which must conflict
4878 * with an SELECTs currently using the view.
4879 */
4882 break;
4883
4884 /*
4885 * These subcommands affect general strategies for performance
4886 * and maintenance, though don't change the semantic results
4887 * from normal data reads and writes. Delaying an ALTER TABLE
4888 * behind currently active writes only delays the point where
4889 * the new strategy begins to take effect, so there is no
4890 * benefit in waiting. In this case the minimum restriction
4891 * applies: we don't currently allow concurrent catalog
4892 * updates.
4893 */
4894 case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4895 case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4896 case AT_DropCluster: /* Uses MVCC in getIndexes() */
4897 case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4898 case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4900 break;
4901
4902 case AT_SetLogged:
4903 case AT_SetUnLogged:
4905 break;
4906
4907 case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4909 break;
4910
4911 /*
4912 * Rel options are more complex than first appears. Options
4913 * are set here for tables, views and indexes; for historical
4914 * reasons these can all be used with ALTER TABLE, so we can't
4915 * decide between them using the basic grammar.
4916 */
4917 case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4918 * getTables() */
4919 case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4920 * getTables() */
4922 break;
4923
4924 case AT_AttachPartition:
4926 break;
4927
4928 case AT_DetachPartition:
4929 if (((PartitionCmd *) cmd->def)->concurrent)
4931 else
4933 break;
4934
4937 break;
4938
4939 case AT_MergePartitions:
4940 case AT_SplitPartition:
4942 break;
4943
4944 default: /* oops */
4945 elog(ERROR, "unrecognized alter table type: %d",
4946 (int) cmd->subtype);
4947 break;
4948 }
4949
4950 /*
4951 * Take the greatest lockmode from any subcommand
4952 */
4953 if (cmd_lockmode > lockmode)
4954 lockmode = cmd_lockmode;
4955 }
4956
4957 return lockmode;
4958}
int LOCKMODE
Definition lockdefs.h:26
#define AccessExclusiveLock
Definition lockdefs.h:43
#define ShareRowExclusiveLock
Definition lockdefs.h:41
#define ShareUpdateExclusiveLock
Definition lockdefs.h:39
#define IsA(nodeptr, _type_)
Definition nodes.h:162
@ CONSTR_FOREIGN
@ CONSTR_UNIQUE
@ CONSTR_EXCLUSION
@ CONSTR_PRIMARY
@ AT_AddIndexConstraint
@ AT_MergePartitions
@ AT_DropOf
@ AT_SetOptions
@ AT_DropIdentity
@ AT_DisableTrigUser
@ AT_DropNotNull
@ AT_AddOf
@ AT_ResetOptions
@ AT_ReplicaIdentity
@ AT_ReplaceRelOptions
@ AT_EnableRowSecurity
@ AT_AddColumnToView
@ AT_ResetRelOptions
@ AT_EnableReplicaTrig
@ AT_DropOids
@ AT_SetIdentity
@ AT_SetUnLogged
@ AT_DisableTrig
@ AT_SetCompression
@ AT_DropExpression
@ AT_AddIndex
@ AT_EnableReplicaRule
@ AT_DropConstraint
@ AT_SetNotNull
@ AT_ClusterOn
@ AT_AddIdentity
@ AT_ForceRowSecurity
@ AT_EnableAlwaysRule
@ AT_SetAccessMethod
@ AT_AlterColumnType
@ AT_DetachPartitionFinalize
@ AT_AddInherit
@ AT_ReAddDomainConstraint
@ AT_EnableTrig
@ AT_DropColumn
@ AT_AlterColumnGenericOptions
@ AT_DisableTrigAll
@ AT_EnableRule
@ AT_NoForceRowSecurity
@ AT_DetachPartition
@ AT_SetStatistics
@ AT_AttachPartition
@ AT_AddConstraint
@ AT_DropInherit
@ AT_EnableAlwaysTrig
@ AT_SetLogged
@ AT_SetStorage
@ AT_DisableRule
@ AT_DisableRowSecurity
@ AT_SetRelOptions
@ AT_ChangeOwner
@ AT_EnableTrigUser
@ AT_SetExpression
@ AT_ReAddConstraint
@ AT_SetTableSpace
@ AT_GenericOptions
@ AT_ColumnDefault
@ AT_CookedColumnDefault
@ AT_AlterConstraint
@ AT_EnableTrigAll
@ AT_SplitPartition
@ AT_DropCluster
@ AT_ValidateConstraint
@ AT_AddColumn
#define lfirst(lc)
Definition pg_list.h:172
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
AlterTableType subtype
Definition pg_list.h:54

References AccessExclusiveLock, AlterTableGetRelOptionsLockLevel(), AT_AddColumn, AT_AddColumnToView, AT_AddConstraint, AT_AddIdentity, AT_AddIndex, AT_AddIndexConstraint, AT_AddInherit, AT_AddOf, AT_AlterColumnGenericOptions, AT_AlterColumnType, AT_AlterConstraint, AT_AttachPartition, AT_ChangeOwner, AT_ClusterOn, AT_ColumnDefault, AT_CookedColumnDefault, AT_DetachPartition, AT_DetachPartitionFinalize, AT_DisableRowSecurity, AT_DisableRule, AT_DisableTrig, AT_DisableTrigAll, AT_DisableTrigUser, AT_DropCluster, AT_DropColumn, AT_DropConstraint, AT_DropExpression, AT_DropIdentity, AT_DropInherit, AT_DropNotNull, AT_DropOf, AT_DropOids, AT_EnableAlwaysRule, AT_EnableAlwaysTrig, AT_EnableReplicaRule, AT_EnableReplicaTrig, AT_EnableRowSecurity, AT_EnableRule, AT_EnableTrig, AT_EnableTrigAll, AT_EnableTrigUser, AT_ForceRowSecurity, AT_GenericOptions, AT_MergePartitions, AT_NoForceRowSecurity, AT_ReAddConstraint, AT_ReAddDomainConstraint, AT_ReplaceRelOptions, AT_ReplicaIdentity, AT_ResetOptions, AT_ResetRelOptions, AT_SetAccessMethod, AT_SetCompression, AT_SetExpression, AT_SetIdentity, AT_SetLogged, AT_SetNotNull, AT_SetOptions, AT_SetRelOptions, AT_SetStatistics, AT_SetStorage, AT_SetTableSpace, AT_SetUnLogged, AT_SplitPartition, AT_ValidateConstraint, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_PRIMARY, CONSTR_UNIQUE, Constraint::contype, AlterTableCmd::def, elog, ERROR, fb(), IsA, lfirst, ShareRowExclusiveLock, ShareUpdateExclusiveLock, and AlterTableCmd::subtype.

Referenced by AlterTableInternal(), and ProcessUtilitySlow().

◆ AlterTableInternal()

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

Definition at line 4655 of file tablecmds.c.

4656{
4657 Relation rel;
4658 LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4659
4660 rel = relation_open(relid, lockmode);
4661
4663
4664 ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4665}
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition tablecmds.c:4700

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)
extern

Definition at line 4567 of file tablecmds.c.

4568{
4569 return RangeVarGetRelidExtended(stmt->relation, lockmode,
4570 stmt->missing_ok ? RVR_MISSING_OK : 0,
4572 stmt);
4573}
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition namespace.c:442
@ RVR_MISSING_OK
Definition namespace.h:90
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)

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

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)
extern

Definition at line 17691 of file tablecmds.c.

17692{
17693 List *relations = NIL;
17694 ListCell *l;
17695 ScanKeyData key[1];
17696 Relation rel;
17697 TableScanDesc scan;
17698 HeapTuple tuple;
17701 List *role_oids = roleSpecsToIds(stmt->roles);
17702
17703 /* Ensure we were not asked to move something we can't */
17704 if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
17705 stmt->objtype != OBJECT_MATVIEW)
17706 ereport(ERROR,
17708 errmsg("only tables, indexes, and materialized views exist in tablespaces")));
17709
17710 /* Get the orig and new tablespace OIDs */
17711 orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
17712 new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
17713
17714 /* Can't move shared relations in to or out of pg_global */
17715 /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
17718 ereport(ERROR,
17720 errmsg("cannot move relations in to or out of pg_global tablespace")));
17721
17722 /*
17723 * Must have CREATE rights on the new tablespace, unless it is the
17724 * database default tablespace (which all users implicitly have CREATE
17725 * rights on).
17726 */
17728 {
17730
17732 ACL_CREATE);
17733 if (aclresult != ACLCHECK_OK)
17736 }
17737
17738 /*
17739 * Now that the checks are done, check if we should set either to
17740 * InvalidOid because it is our database's default tablespace.
17741 */
17744
17747
17748 /* no-op */
17750 return new_tablespaceoid;
17751
17752 /*
17753 * Walk the list of objects in the tablespace and move them. This will
17754 * only find objects in our database, of course.
17755 */
17756 ScanKeyInit(&key[0],
17760
17762 scan = table_beginscan_catalog(rel, 1, key);
17763 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
17764 {
17766 Oid relOid = relForm->oid;
17767
17768 /*
17769 * Do not move objects in pg_catalog as part of this, if an admin
17770 * really wishes to do so, they can issue the individual ALTER
17771 * commands directly.
17772 *
17773 * Also, explicitly avoid any shared tables, temp tables, TOAST (TOAST
17774 * will be moved with the main table).
17775 *
17776 * Conflict log tables are system-managed for logical replication and
17777 * cannot be altered directly, so skip them as well; otherwise a
17778 * single such table in the source tablespace would abort the whole
17779 * bulk move.
17780 */
17781 if (IsCatalogNamespace(relForm->relnamespace) ||
17782 relForm->relisshared ||
17783 isAnyTempNamespace(relForm->relnamespace) ||
17784 IsToastNamespace(relForm->relnamespace) ||
17785 IsConflictLogTableNamespace(relForm->relnamespace))
17786 continue;
17787
17788 /* Only move the object type requested */
17789 if ((stmt->objtype == OBJECT_TABLE &&
17790 relForm->relkind != RELKIND_RELATION &&
17791 relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
17792 (stmt->objtype == OBJECT_INDEX &&
17793 relForm->relkind != RELKIND_INDEX &&
17794 relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
17795 (stmt->objtype == OBJECT_MATVIEW &&
17796 relForm->relkind != RELKIND_MATVIEW))
17797 continue;
17798
17799 /* Check if we are only moving objects owned by certain roles */
17800 if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
17801 continue;
17802
17803 /*
17804 * Handle permissions-checking here since we are locking the tables
17805 * and also to avoid doing a bunch of work only to fail part-way. Note
17806 * that permissions will also be checked by AlterTableInternal().
17807 *
17808 * Caller must be considered an owner on the table to move it.
17809 */
17812 NameStr(relForm->relname));
17813
17814 if (stmt->nowait &&
17816 ereport(ERROR,
17818 errmsg("aborting because lock on relation \"%s.%s\" is not available",
17819 get_namespace_name(relForm->relnamespace),
17820 NameStr(relForm->relname))));
17821 else
17823
17824 /* Add to our list of objects to move */
17825 relations = lappend_oid(relations, relOid);
17826 }
17827
17828 table_endscan(scan);
17830
17831 if (relations == NIL)
17834 errmsg("no matching relations in tablespace \"%s\" found",
17835 orig_tablespaceoid == InvalidOid ? "(database default)" :
17837
17838 /* Everything is locked, loop through and move all of the relations. */
17839 foreach(l, relations)
17840 {
17841 List *cmds = NIL;
17843
17845 cmd->name = stmt->new_tablespacename;
17846
17847 cmds = lappend(cmds, cmd);
17848
17850 /* OID is set by AlterTableInternal */
17851 AlterTableInternal(lfirst_oid(l), cmds, false);
17853 }
17854
17855 return new_tablespaceoid;
17856}
AclResult
Definition acl.h:183
@ ACLCHECK_OK
Definition acl.h:184
@ ACLCHECK_NOT_OWNER
Definition acl.h:186
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition aclchk.c:3902
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4156
char * get_tablespace_name(Oid spc_oid)
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
#define OidIsValid(objectId)
Definition c.h:917
bool IsToastNamespace(Oid namespaceId)
Definition catalog.c:277
bool IsConflictLogTableNamespace(Oid namespaceId)
Definition catalog.c:290
bool IsCatalogNamespace(Oid namespaceId)
Definition catalog.c:259
#define NOTICE
Definition elog.h:36
void EventTriggerAlterTableStart(const Node *parsetree)
void EventTriggerAlterTableEnd(void)
Oid MyDatabaseTableSpace
Definition globals.c:98
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition heapam.c:1436
List * lappend(List *list, void *datum)
Definition list.c:339
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
bool list_member_oid(const List *list, Oid datum)
Definition list.c:722
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition lmgr.c:151
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition lmgr.c:107
#define AccessShareLock
Definition lockdefs.h:36
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2317
Oid GetUserId(void)
Definition miscinit.c:470
bool isAnyTempNamespace(Oid namespaceId)
Definition namespace.c:3759
#define makeNode(_type_)
Definition nodes.h:159
ObjectType get_relkind_objtype(char relkind)
@ OBJECT_MATVIEW
@ OBJECT_TABLESPACE
@ OBJECT_INDEX
@ OBJECT_TABLE
#define ACL_CREATE
Definition parsenodes.h:85
#define NIL
Definition pg_list.h:68
#define lfirst_oid(lc)
Definition pg_list.h:174
unsigned int Oid
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
@ ForwardScanDirection
Definition sdir.h:28
#define BTEqualStrategyNumber
Definition stratnum.h:31
Definition nodes.h:133
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, ScanKeyData *key)
Definition tableam.c:113
static void table_endscan(TableScanDesc scan)
Definition tableam.h:1061
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition tablecmds.c:4655
List * roleSpecsToIds(List *memberNames)
Definition user.c:1665

References AccessExclusiveLock, AccessShareLock, ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTableInternal(), AT_SetTableSpace, BTEqualStrategyNumber, ConditionalLockRelationOid(), ereport, errcode(), errmsg, ERROR, EventTriggerAlterTableEnd(), EventTriggerAlterTableStart(), fb(), ForwardScanDirection, get_namespace_name(), get_rel_relkind(), get_relkind_objtype(), get_tablespace_name(), get_tablespace_oid(), GETSTRUCT(), GetUserId(), heap_getnext(), InvalidOid, isAnyTempNamespace(), IsCatalogNamespace(), IsConflictLogTableNamespace(), IsToastNamespace(), lappend(), lappend_oid(), lfirst_oid, list_member_oid(), LockRelationOid(), makeNode, MyDatabaseTableSpace, AlterTableCmd::name, NameStr, NIL, NOTICE, object_aclcheck(), OBJECT_INDEX, OBJECT_MATVIEW, object_ownercheck(), OBJECT_TABLE, OBJECT_TABLESPACE, ObjectIdGetDatum(), OidIsValid, roleSpecsToIds(), ScanKeyInit(), stmt, AlterTableCmd::subtype, table_beginscan_catalog(), table_close(), table_endscan(), and table_open().

Referenced by ProcessUtilitySlow().

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)
extern

Definition at line 19649 of file tablecmds.c.

19650{
19651 Relation rel;
19652 Oid relid;
19653 Oid oldNspOid;
19654 Oid nspOid;
19655 RangeVar *newrv;
19658
19660 stmt->missing_ok ? RVR_MISSING_OK : 0,
19662 stmt);
19663
19664 if (!OidIsValid(relid))
19665 {
19667 (errmsg("relation \"%s\" does not exist, skipping",
19668 stmt->relation->relname)));
19669 return InvalidObjectAddress;
19670 }
19671
19672 rel = relation_open(relid, NoLock);
19673
19675
19676 /* If it's an owned sequence, disallow moving it by itself. */
19677 if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
19678 {
19679 Oid tableId;
19680 int32 colId;
19681
19682 if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
19684 ereport(ERROR,
19686 errmsg("cannot move an owned sequence into another schema"),
19687 errdetail("Sequence \"%s\" is linked to table \"%s\".",
19690 }
19691
19692 /* Get and lock schema OID and check its permissions. */
19693 newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
19695
19696 /* common checks on switching namespaces */
19698
19702
19704
19705 if (oldschema)
19707
19708 /* close rel, but keep lock until commit */
19709 relation_close(rel, NoLock);
19710
19711 return myself;
19712}
int32_t int32
Definition c.h:679
ObjectAddresses * new_object_addresses(void)
void free_object_addresses(ObjectAddresses *addrs)
@ DEPENDENCY_AUTO
Definition dependency.h:34
@ DEPENDENCY_INTERNAL
Definition dependency.h:35
int errdetail(const char *fmt,...) pg_attribute_printf(1
char * get_rel_name(Oid relid)
Definition lsyscache.c:2242
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition makefuncs.c:473
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition namespace.c:740
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition namespace.c:3531
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition pg_depend.c:1032
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationGetNamespace(relation)
Definition rel.h:557
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:206
Form_pg_class rd_rel
Definition rel.h:111
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)

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

Referenced by ExecAlterObjectSchemaStmt().

◆ AlterTableNamespaceInternal()

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

Definition at line 19720 of file tablecmds.c.

19722{
19724
19725 Assert(objsMoved != NULL);
19726
19727 /* OK, modify the pg_class row and pg_depend entry */
19729
19731 nspOid, true, objsMoved);
19732
19733 /* Fix the table's row type too, if it has one */
19734 if (OidIsValid(rel->rd_rel->reltype))
19736 false, /* isImplicitArray */
19737 false, /* ignoreDependent */
19738 false, /* errorOnTableType */
19739 objsMoved);
19740
19741 /* Fix other dependent stuff */
19746 false, objsMoved);
19747
19749}
#define RowExclusiveLock
Definition lockdefs.h:38
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
#define RelationGetRelid(relation)
Definition rel.h:516
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition typecmds.c:4195

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

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 20162 of file tablecmds.c.

20164{
20166
20167 foreach(cur_item, on_commits)
20168 {
20170
20171 if (!isCommit && oc->creating_subid == mySubid)
20172 {
20173 /* cur_item must be removed */
20175 pfree(oc);
20176 }
20177 else
20178 {
20179 /* cur_item must be preserved */
20180 if (oc->creating_subid == mySubid)
20181 oc->creating_subid = parentSubid;
20182 if (oc->deleting_subid == mySubid)
20183 oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
20184 }
20185 }
20186}
#define InvalidSubTransactionId
Definition c.h:801
void pfree(void *pointer)
Definition mcxt.c:1619
#define foreach_delete_current(lst, var_or_cell)
Definition pg_list.h:423
static List * on_commits
Definition tablecmds.c:135

References fb(), foreach_delete_current, InvalidSubTransactionId, lfirst, on_commits, and pfree().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)
extern

Definition at line 20130 of file tablecmds.c.

20131{
20133
20134 foreach(cur_item, on_commits)
20135 {
20137
20138 if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
20139 oc->creating_subid != InvalidSubTransactionId)
20140 {
20141 /* cur_item must be removed */
20143 pfree(oc);
20144 }
20145 else
20146 {
20147 /* cur_item must be preserved */
20148 oc->creating_subid = InvalidSubTransactionId;
20149 oc->deleting_subid = InvalidSubTransactionId;
20150 }
20151 }
20152}

References fb(), foreach_delete_current, InvalidSubTransactionId, lfirst, on_commits, and pfree().

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

◆ ATExecChangeOwner()

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

Definition at line 16777 of file tablecmds.c.

16778{
16781 HeapTuple tuple;
16783
16784 /*
16785 * Get exclusive lock till end of transaction on the target table. Use
16786 * relation_open so that we can work on indexes and sequences.
16787 */
16788 target_rel = relation_open(relationOid, lockmode);
16789
16790 /* Get its pg_class tuple, too */
16792
16793 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
16794 if (!HeapTupleIsValid(tuple))
16795 elog(ERROR, "cache lookup failed for relation %u", relationOid);
16797
16798 /* Can we change the ownership of this tuple? */
16799 switch (tuple_class->relkind)
16800 {
16801 case RELKIND_RELATION:
16802 case RELKIND_VIEW:
16803 case RELKIND_MATVIEW:
16806 case RELKIND_PROPGRAPH:
16807 /* ok to change owner */
16808 break;
16809 case RELKIND_INDEX:
16810 if (!recursing)
16811 {
16812 /*
16813 * Because ALTER INDEX OWNER used to be allowed, and in fact
16814 * is generated by old versions of pg_dump, we give a warning
16815 * and do nothing rather than erroring out. Also, to avoid
16816 * unnecessary chatter while restoring those old dumps, say
16817 * nothing at all if the command would be a no-op anyway.
16818 */
16819 if (tuple_class->relowner != newOwnerId)
16822 errmsg("cannot change owner of index \"%s\"",
16823 NameStr(tuple_class->relname)),
16824 errhint("Change the ownership of the index's table instead.")));
16825 /* quick hack to exit via the no-op path */
16826 newOwnerId = tuple_class->relowner;
16827 }
16828 break;
16830 if (recursing)
16831 break;
16832 ereport(ERROR,
16834 errmsg("cannot change owner of index \"%s\"",
16835 NameStr(tuple_class->relname)),
16836 errhint("Change the ownership of the index's table instead.")));
16837 break;
16838 case RELKIND_SEQUENCE:
16839 if (!recursing &&
16840 tuple_class->relowner != newOwnerId)
16841 {
16842 /* if it's an owned sequence, disallow changing it by itself */
16843 Oid tableId;
16844 int32 colId;
16845
16846 if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
16848 ereport(ERROR,
16850 errmsg("cannot change owner of sequence \"%s\"",
16851 NameStr(tuple_class->relname)),
16852 errdetail("Sequence \"%s\" is linked to table \"%s\".",
16853 NameStr(tuple_class->relname),
16855 }
16856 break;
16858 if (recursing)
16859 break;
16860 ereport(ERROR,
16862 errmsg("\"%s\" is a composite type",
16863 NameStr(tuple_class->relname)),
16864 /* translator: %s is an SQL ALTER command */
16865 errhint("Use %s instead.",
16866 "ALTER TYPE")));
16867 break;
16868 case RELKIND_TOASTVALUE:
16869 if (recursing)
16870 break;
16872 default:
16873 ereport(ERROR,
16875 errmsg("cannot change owner of relation \"%s\"",
16876 NameStr(tuple_class->relname)),
16878 }
16879
16880 /*
16881 * If the new owner is the same as the existing owner, consider the
16882 * command to have succeeded. This is for dump restoration purposes.
16883 */
16884 if (tuple_class->relowner != newOwnerId)
16885 {
16889 Acl *newAcl;
16891 bool isNull;
16892 HeapTuple newtuple;
16893
16894 /* skip permission checks when recursing to index or toast table */
16895 if (!recursing)
16896 {
16897 /* Superusers can always do it */
16898 if (!superuser())
16899 {
16900 Oid namespaceOid = tuple_class->relnamespace;
16902
16903 /* Otherwise, must be owner of the existing object */
16904 if (!object_ownercheck(RelationRelationId, relationOid, GetUserId()))
16907
16908 /* Must be able to become new owner */
16910
16911 /* New owner must have CREATE privilege on namespace */
16913 ACL_CREATE);
16914 if (aclresult != ACLCHECK_OK)
16917 }
16918 }
16919
16920 memset(repl_null, false, sizeof(repl_null));
16921 memset(repl_repl, false, sizeof(repl_repl));
16922
16925
16926 /*
16927 * Determine the modified ACL for the new owner. This is only
16928 * necessary when the ACL is non-null.
16929 */
16932 &isNull);
16933 if (!isNull)
16934 {
16936 tuple_class->relowner, newOwnerId);
16937 repl_repl[Anum_pg_class_relacl - 1] = true;
16939 }
16940
16942
16943 CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
16944
16945 heap_freetuple(newtuple);
16946
16947 /*
16948 * We must similarly update any per-column ACLs to reflect the new
16949 * owner; for neatness reasons that's split out as a subroutine.
16950 */
16951 change_owner_fix_column_acls(relationOid,
16952 tuple_class->relowner,
16953 newOwnerId);
16954
16955 /*
16956 * Update owner dependency reference, if any. A composite type has
16957 * none, because it's tracked for the pg_type entry instead of here;
16958 * indexes and TOAST tables don't have their own entries either.
16959 */
16960 if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
16961 tuple_class->relkind != RELKIND_INDEX &&
16963 tuple_class->relkind != RELKIND_TOASTVALUE)
16965 newOwnerId);
16966
16967 /*
16968 * Also change the ownership of the table's row type, if it has one
16969 */
16970 if (OidIsValid(tuple_class->reltype))
16972
16973 /*
16974 * If we are operating on a table or materialized view, also change
16975 * the ownership of any indexes and sequences that belong to the
16976 * relation, as well as its toast table (if it has one).
16977 */
16978 if (tuple_class->relkind == RELKIND_RELATION ||
16980 tuple_class->relkind == RELKIND_MATVIEW ||
16981 tuple_class->relkind == RELKIND_TOASTVALUE)
16982 {
16984 ListCell *i;
16985
16986 /* Find all the indexes belonging to this relation */
16988
16989 /* For each index, recursively change its ownership */
16990 foreach(i, index_oid_list)
16991 ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
16992
16994 }
16995
16996 /* If it has a toast table, recurse to change its ownership */
16997 if (tuple_class->reltoastrelid != InvalidOid)
16999 true, lockmode);
17000
17001 /* If it has dependent sequences, recurse to change them too */
17002 change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
17003 }
17004
17006
17007 ReleaseSysCache(tuple);
17010}
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition acl.c:1150
void check_can_set_role(Oid member, Oid role)
Definition acl.c:5374
#define DatumGetAclP(X)
Definition acl.h:120
#define pg_fallthrough
Definition c.h:220
int errhint(const char *fmt,...) pg_attribute_printf(1
#define WARNING
Definition elog.h:37
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1118
int i
Definition isn.c:77
void list_free(List *list)
Definition list.c:1546
@ OBJECT_SCHEMA
int errdetail_relkind_not_supported(char relkind)
Definition pg_class.c:24
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
uint64_t Datum
Definition postgres.h:70
#define PointerGetDatum(X)
Definition postgres.h:354
#define RelationGetDescr(relation)
Definition rel.h:542
List * RelationGetIndexList(Relation relation)
Definition relcache.c:4848
ItemPointerData t_self
Definition htup.h:65
bool superuser(void)
Definition superuser.c:47
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition typecmds.c:4026

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_can_set_role(), DatumGetAclP, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, elog, ereport, errcode(), errdetail(), errdetail_relkind_not_supported(), errhint(), errmsg, ERROR, fb(), get_namespace_name(), get_rel_name(), get_rel_relkind(), get_relkind_objtype(), GETSTRUCT(), GetUserId(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, i, InvalidOid, InvokeObjectPostAlterHook, lfirst_oid, list_free(), NameStr, NoLock, object_aclcheck(), object_ownercheck(), OBJECT_SCHEMA, ObjectIdGetDatum(), OidIsValid, pg_fallthrough, PointerGetDatum, relation_close(), relation_open(), RelationGetDescr, RelationGetIndexList(), RelationGetRelationName, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), sequenceIsOwned(), superuser(), SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), and WARNING.

Referenced by AlterSubscriptionOwner_internal(), AlterTypeOwner_oid(), ATExecChangeOwner(), ATExecCmd(), change_owner_recurse_to_sequences(), and shdepReassignOwned_Owner().

◆ BuildDescForRelation()

TupleDesc BuildDescForRelation ( const List columns)
extern

Definition at line 1437 of file tablecmds.c.

1438{
1439 int natts;
1441 ListCell *l;
1442 TupleDesc desc;
1443 char *attname;
1444 Oid atttypid;
1445 int32 atttypmod;
1446 Oid attcollation;
1447 int attdim;
1448
1449 /*
1450 * allocate a new tuple descriptor
1451 */
1452 natts = list_length(columns);
1453 desc = CreateTemplateTupleDesc(natts);
1454
1455 attnum = 0;
1456
1457 foreach(l, columns)
1458 {
1459 ColumnDef *entry = lfirst(l);
1462
1463 /*
1464 * for each entry in the list, get the name and type information from
1465 * the list and have TupleDescInitEntry fill in the attribute
1466 * information we need.
1467 */
1468 attnum++;
1469
1470 attname = entry->colname;
1471 typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
1472
1474 if (aclresult != ACLCHECK_OK)
1475 aclcheck_error_type(aclresult, atttypid);
1476
1477 attcollation = GetColumnDefCollation(NULL, entry, atttypid);
1479 if (attdim > PG_INT16_MAX)
1480 ereport(ERROR,
1482 errmsg("too many array dimensions"));
1483
1484 if (entry->typeName->setof)
1485 ereport(ERROR,
1487 errmsg("column \"%s\" cannot be declared SETOF",
1488 attname)));
1489
1491 atttypid, atttypmod, attdim);
1492 att = TupleDescAttr(desc, attnum - 1);
1493
1494 /* Override TupleDescInitEntry's settings as requested */
1495 TupleDescInitEntryCollation(desc, attnum, attcollation);
1496
1497 /* Fill in additional stuff not handled by TupleDescInitEntry */
1498 att->attnotnull = entry->is_not_null;
1499 att->attislocal = entry->is_local;
1500 att->attinhcount = entry->inhcount;
1501 att->attidentity = entry->identity;
1502 att->attgenerated = entry->generated;
1503 att->attcompression = GetAttributeCompression(att->atttypid, entry->compression);
1504 if (entry->storage)
1505 att->attstorage = entry->storage;
1506 else if (entry->storage_name)
1507 att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name);
1508
1510 }
1511
1512 TupleDescFinalize(desc);
1513
1514 return desc;
1515}
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition aclchk.c:2997
int16 AttrNumber
Definition attnum.h:21
#define PG_INT16_MAX
Definition c.h:729
void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, Oid *typeid_p, int32 *typmod_p)
Definition parse_type.c:310
Oid GetColumnDefCollation(ParseState *pstate, const ColumnDef *coldef, Oid typeOid)
Definition parse_type.c:540
#define ACL_USAGE
Definition parsenodes.h:84
NameData attname
int16 attnum
FormData_pg_attribute * Form_pg_attribute
static int list_length(const List *l)
Definition pg_list.h:152
bool is_not_null
Definition parsenodes.h:776
char identity
Definition parsenodes.h:782
char * storage_name
Definition parsenodes.h:779
char * colname
Definition parsenodes.h:771
TypeName * typeName
Definition parsenodes.h:772
char generated
Definition parsenodes.h:785
char storage
Definition parsenodes.h:778
bool is_local
Definition parsenodes.h:775
int16 inhcount
Definition parsenodes.h:774
char * compression
Definition parsenodes.h:773
bool setof
Definition parsenodes.h:291
List * arrayBounds
Definition parsenodes.h:295
static char GetAttributeCompression(Oid atttypid, const char *compression)
static char GetAttributeStorage(Oid atttypid, const char *storagemode)
TupleDesc CreateTemplateTupleDesc(int natts)
Definition tupdesc.c:165
void TupleDescFinalize(TupleDesc tupdesc)
Definition tupdesc.c:511
void populate_compact_attribute(TupleDesc tupdesc, int attnum)
Definition tupdesc.c:100
void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid)
Definition tupdesc.c:1093
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition tupdesc.c:909
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, TypeName::arrayBounds, attname, attnum, ColumnDef::colname, ColumnDef::compression, CreateTemplateTupleDesc(), ereport, errcode(), errmsg, ERROR, fb(), ColumnDef::generated, GetAttributeCompression(), GetAttributeStorage(), GetColumnDefCollation(), GetUserId(), ColumnDef::identity, ColumnDef::inhcount, ColumnDef::is_local, ColumnDef::is_not_null, lfirst, list_length(), object_aclcheck(), PG_INT16_MAX, populate_compact_attribute(), TypeName::setof, ColumnDef::storage, ColumnDef::storage_name, TupleDescAttr(), TupleDescFinalize(), TupleDescInitEntry(), TupleDescInitEntryCollation(), ColumnDef::typeName, and typenameTypeIdAndMod().

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

◆ check_of_type()

void check_of_type ( HeapTuple  typetuple)
extern

Definition at line 7284 of file tablecmds.c.

7285{
7287 bool typeOk = false;
7288
7289 if (typ->typtype == TYPTYPE_COMPOSITE)
7290 {
7292
7293 Assert(OidIsValid(typ->typrelid));
7295 typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
7296
7297 /*
7298 * Close the parent rel, but keep our AccessShareLock on it until xact
7299 * commit. That will prevent someone else from deleting or ALTERing
7300 * the type before the typed table creation/conversion commits.
7301 */
7303
7304 if (!typeOk)
7305 ereport(ERROR,
7307 errmsg("type %s is the row type of another table",
7308 format_type_be(typ->oid)),
7309 errdetail("A typed table must use a stand-alone composite type created with CREATE TYPE.")));
7310 }
7311 else
7312 ereport(ERROR,
7314 errmsg("type %s is not a composite type",
7315 format_type_be(typ->oid))));
7316}
char * format_type_be(Oid type_oid)
END_CATALOG_STRUCT typedef FormData_pg_type * Form_pg_type
Definition pg_type.h:265

References AccessShareLock, Assert, ereport, errcode(), errdetail(), errmsg, ERROR, fb(), Form_pg_type, format_type_be(), GETSTRUCT(), NoLock, OidIsValid, relation_close(), and relation_open().

Referenced by ATExecAddOf(), and transformOfType().

◆ CheckRelationTableSpaceMove()

bool CheckRelationTableSpaceMove ( Relation  rel,
Oid  newTableSpaceId 
)
extern

Definition at line 3772 of file tablecmds.c.

3773{
3775
3776 /*
3777 * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3778 * stored as 0.
3779 */
3780 oldTableSpaceId = rel->rd_rel->reltablespace;
3783 return false;
3784
3785 /*
3786 * We cannot support moving mapped relations into different tablespaces.
3787 * (In particular this eliminates all shared catalogs.)
3788 */
3789 if (RelationIsMapped(rel))
3790 ereport(ERROR,
3792 errmsg("cannot move system relation \"%s\"",
3794
3795 /* Cannot move a non-shared relation into pg_global */
3797 ereport(ERROR,
3799 errmsg("only shared relations can be placed in pg_global tablespace")));
3800
3801 /*
3802 * Do not allow moving temp tables of other backends ... their local
3803 * buffer manager is not going to cope.
3804 */
3805 if (RELATION_IS_OTHER_TEMP(rel))
3806 ereport(ERROR,
3808 errmsg("cannot move temporary tables of other sessions")));
3809
3810 return true;
3811}
#define RelationIsMapped(relation)
Definition rel.h:565
#define RELATION_IS_OTHER_TEMP(relation)
Definition rel.h:678

References ereport, errcode(), errmsg, ERROR, fb(), MyDatabaseTableSpace, RelationData::rd_rel, RELATION_IS_OTHER_TEMP, RelationGetRelationName, and RelationIsMapped.

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

◆ CheckTableNotInUse()

void CheckTableNotInUse ( Relation  rel,
const char stmt 
)
extern

Definition at line 4508 of file tablecmds.c.

4509{
4510 int expected_refcnt;
4511
4512 expected_refcnt = rel->rd_isnailed ? 2 : 1;
4513 if (rel->rd_refcnt != expected_refcnt)
4514 ereport(ERROR,
4516 /* translator: first %s is a SQL command, eg ALTER TABLE */
4517 errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
4519
4520 if (rel->rd_rel->relkind != RELKIND_INDEX &&
4521 rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
4523 ereport(ERROR,
4525 /* translator: first %s is a SQL command, eg ALTER TABLE */
4526 errmsg("cannot %s \"%s\" because it has pending trigger events",
4528}
int rd_refcnt
Definition rel.h:59
bool rd_isnailed
Definition rel.h:62
bool AfterTriggerPendingOnRel(Oid relid)
Definition trigger.c:6175

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

Referenced by CheckAlterTableIsSafe(), cluster_rel(), DefineIndex(), DefineVirtualRelation(), heap_drop_with_catalog(), index_drop(), MergeAttributes(), RefreshMatViewByOid(), reindex_index(), and truncate_check_activity().

◆ DefineRelation()

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

Definition at line 818 of file tablecmds.c.

820{
821 char relname[NAMEDATALEN];
825 Relation rel;
832 List *nncols;
833 List *connames = NIL;
834 Datum reloptions;
837 bool partitioned;
838 const char *const validnsps[] = HEAP_RELOPT_NAMESPACES;
840 ObjectAddress address;
843
844 /*
845 * Truncate relname to appropriate length (probably a waste of time, as
846 * parser should have done this already).
847 */
848 strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
849
850 /*
851 * Check consistency of arguments
852 */
853 if (stmt->oncommit != ONCOMMIT_NOOP
854 && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
857 errmsg("ON COMMIT can only be used on temporary tables")));
858
859 if (stmt->partspec != NULL)
860 {
861 if (relkind != RELKIND_RELATION)
862 elog(ERROR, "unexpected relkind: %d", (int) relkind);
863
865 partitioned = true;
866 }
867 else
868 partitioned = false;
869
870 if (relkind == RELKIND_PARTITIONED_TABLE &&
871 stmt->relation->relpersistence == RELPERSISTENCE_UNLOGGED)
874 errmsg("partitioned tables cannot be unlogged")));
875
876 /*
877 * Look up the namespace in which we are supposed to create the relation,
878 * check we have permission to create there, lock it against concurrent
879 * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
880 * namespace is selected.
881 */
884
885 /*
886 * Security check: disallow creating temp tables from security-restricted
887 * code. This is needed because calling code might not expect untrusted
888 * tables to appear in pg_temp at the front of its search path.
889 */
890 if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
894 errmsg("cannot create temporary table within security-restricted operation")));
895
896 /*
897 * Determine the lockmode to use when scanning parents. A self-exclusive
898 * lock is needed here.
899 *
900 * For regular inheritance, if two backends attempt to add children to the
901 * same parent simultaneously, and that parent has no pre-existing
902 * children, then both will attempt to update the parent's relhassubclass
903 * field, leading to a "tuple concurrently updated" error. Also, this
904 * interlocks against a concurrent ANALYZE on the parent table, which
905 * might otherwise be attempting to clear the parent's relhassubclass
906 * field, if its previous children were recently dropped.
907 *
908 * If the child table is a partition, then we instead grab an exclusive
909 * lock on the parent because its partition descriptor will be changed by
910 * addition of the new partition.
911 */
912 parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
914
915 /* Determine the list of OIDs of the parents. */
917 foreach(listptr, stmt->inhRelations)
918 {
919 RangeVar *rv = (RangeVar *) lfirst(listptr);
921
923
924 /*
925 * Reject duplications in the list of parents.
926 */
930 errmsg("relation \"%s\" would be inherited from more than once",
932
934 }
935
936 /*
937 * Select tablespace to use: an explicitly indicated one, or (in the case
938 * of a partitioned table) the parent's, if it has one.
939 */
940 if (stmt->tablespacename)
941 {
942 tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
943
947 errmsg("cannot specify default tablespace for partitioned relations")));
948 }
949 else if (stmt->partbound)
950 {
953 }
954 else
956
957 /* still nothing? use the default */
959 tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
961
962 /* Check permissions except when using database's default */
964 {
966
968 ACL_CREATE);
969 if (aclresult != ACLCHECK_OK)
972 }
973
974 /* In all cases disallow placing user relations in pg_global */
978 errmsg("only shared relations can be placed in pg_global tablespace")));
979
980 /* Identify user ID that will own the table */
981 if (!OidIsValid(ownerId))
982 ownerId = GetUserId();
983
984 /*
985 * Parse and validate reloptions, if any.
986 */
987 reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
988 true, false);
989
990 switch (relkind)
991 {
992 case RELKIND_VIEW:
993 (void) view_reloptions(reloptions, true);
994 break;
996 (void) partitioned_table_reloptions(reloptions, true);
997 break;
998 default:
999 (void) heap_reloptions(relkind, reloptions, true);
1000 }
1001
1002 if (stmt->ofTypename)
1003 {
1005
1006 ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
1007
1009 if (aclresult != ACLCHECK_OK)
1011 }
1012 else
1014
1015 /*
1016 * Look up inheritance ancestors and generate relation schema, including
1017 * inherited attributes. (Note that stmt->tableElts is destructively
1018 * modified by MergeAttributes.)
1019 */
1020 stmt->tableElts =
1021 MergeAttributes(stmt->tableElts, inheritOids,
1022 stmt->relation->relpersistence,
1023 stmt->partbound != NULL,
1025
1026 /*
1027 * Create a tuple descriptor from the relation schema. Note that this
1028 * deals with column names, types, and in-descriptor NOT NULL flags, but
1029 * not default values, NOT NULL or CHECK constraints; we handle those
1030 * below.
1031 */
1032 descriptor = BuildDescForRelation(stmt->tableElts);
1033
1034 /*
1035 * Find columns with default values and prepare for insertion of the
1036 * defaults. Pre-cooked (that is, inherited) defaults go into a list of
1037 * CookedConstraint structs that we'll pass to heap_create_with_catalog,
1038 * while raw defaults go into a list of RawColumnDefault structs that will
1039 * be processed by AddRelationNewConstraints. (We can't deal with raw
1040 * expressions until we can do transformExpr.)
1041 */
1042 rawDefaults = NIL;
1044 attnum = 0;
1045
1046 foreach(listptr, stmt->tableElts)
1047 {
1049
1050 attnum++;
1051 if (colDef->raw_default != NULL)
1052 {
1054
1055 Assert(colDef->cooked_default == NULL);
1056
1058 rawEnt->attnum = attnum;
1059 rawEnt->raw_default = colDef->raw_default;
1060 rawEnt->generated = colDef->generated;
1062 }
1063 else if (colDef->cooked_default != NULL)
1064 {
1066
1068 cooked->contype = CONSTR_DEFAULT;
1069 cooked->conoid = InvalidOid; /* until created */
1070 cooked->name = NULL;
1071 cooked->attnum = attnum;
1072 cooked->expr = colDef->cooked_default;
1073 cooked->is_enforced = true;
1074 cooked->skip_validation = false;
1075 cooked->is_local = true; /* not used for defaults */
1076 cooked->inhcount = 0; /* ditto */
1077 cooked->is_no_inherit = false;
1079 }
1080 }
1081
1083
1084 /*
1085 * For relations with table AM and partitioned tables, select access
1086 * method to use: an explicitly indicated one, or (in the case of a
1087 * partitioned table) the parent's, if it has one.
1088 */
1089 if (stmt->accessMethod != NULL)
1090 {
1092 accessMethodId = get_table_am_oid(stmt->accessMethod, false);
1093 }
1094 else if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE)
1095 {
1096 if (stmt->partbound)
1097 {
1100 }
1101
1104 }
1105
1106 /*
1107 * Create the relation. Inherited defaults and CHECK constraints are
1108 * passed in for immediate handling --- since they don't need parsing,
1109 * they can be stored immediately.
1110 */
1114 InvalidOid,
1115 InvalidOid,
1116 ofTypeId,
1117 ownerId,
1119 descriptor,
1122 relkind,
1123 stmt->relation->relpersistence,
1124 false,
1125 false,
1126 stmt->oncommit,
1127 reloptions,
1128 true,
1130 false,
1131 InvalidOid,
1132 typaddress);
1133
1134 /*
1135 * We must bump the command counter to make the newly-created relation
1136 * tuple visible for opening.
1137 */
1139
1140 /*
1141 * Open the new relation and acquire exclusive lock on it. This isn't
1142 * really necessary for locking out other backends (since they can't see
1143 * the new rel anyway until we commit), but it keeps the lock manager from
1144 * complaining about deadlock risks.
1145 */
1147
1148 /*
1149 * Now add any newly specified column default and generation expressions
1150 * to the new relation. These are passed to us in the form of raw
1151 * parsetrees; we need to transform them to executable expression trees
1152 * before they can be added. The most convenient way to do that is to
1153 * apply the parser's transformExpr routine, but transformExpr doesn't
1154 * work unless we have a pre-existing relation. So, the transformation has
1155 * to be postponed to this final step of CREATE TABLE.
1156 *
1157 * This needs to be before processing the partitioning clauses because
1158 * those could refer to generated columns.
1159 */
1160 if (rawDefaults)
1162 true, true, false, queryString);
1163
1164 /*
1165 * Make column generation expressions visible for use by partitioning.
1166 */
1168
1169 /* Process and store partition bound, if any. */
1170 if (stmt->partbound)
1171 {
1172 PartitionBoundSpec *bound;
1173 ParseState *pstate;
1176 Relation parent,
1177 defaultRel = NULL;
1179
1180 /* Already have strong enough lock on the parent */
1181 parent = table_open(parentId, NoLock);
1182
1183 /*
1184 * We are going to try to validate the partition bound specification
1185 * against the partition key of parentRel, so it better have one.
1186 */
1187 if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1188 ereport(ERROR,
1190 errmsg("\"%s\" is not partitioned",
1191 RelationGetRelationName(parent))));
1192
1193 /*
1194 * The partition constraint of the default partition depends on the
1195 * partition bounds of every other partition. It is possible that
1196 * another backend might be about to execute a query on the default
1197 * partition table, and that the query relies on previously cached
1198 * default partition constraints. We must therefore take a table lock
1199 * strong enough to prevent all queries on the default partition from
1200 * proceeding until we commit and send out a shared-cache-inval notice
1201 * that will make them update their index lists.
1202 *
1203 * Order of locking: The relation being added won't be visible to
1204 * other backends until it is committed, hence here in
1205 * DefineRelation() the order of locking the default partition and the
1206 * relation being added does not matter. But at all other places we
1207 * need to lock the default relation before we lock the relation being
1208 * added or removed i.e. we should take the lock in same order at all
1209 * the places such that lock parent, lock default partition and then
1210 * lock the partition so as to avoid a deadlock.
1211 */
1214 true));
1217
1218 /* Transform the bound values */
1219 pstate = make_parsestate(NULL);
1220 pstate->p_sourcetext = queryString;
1221
1222 /*
1223 * Add an nsitem containing this relation, so that transformExpr
1224 * called on partition bound expressions is able to report errors
1225 * using a proper context.
1226 */
1228 NULL, false, false);
1229 addNSItemToQuery(pstate, nsitem, false, true, true);
1230
1231 bound = transformPartitionBound(pstate, parent, stmt->partbound);
1232
1233 /*
1234 * Check first that the new partition's bound is valid and does not
1235 * overlap with any of existing partitions of the parent.
1236 */
1237 check_new_partition_bound(relname, parent, bound, pstate);
1238
1239 /*
1240 * If the default partition exists, its partition constraints will
1241 * change after the addition of this new partition such that it won't
1242 * allow any row that qualifies for this new partition. So, check that
1243 * the existing data in the default partition satisfies the constraint
1244 * as it will exist after adding this partition.
1245 */
1247 {
1249 /* Keep the lock until commit. */
1251 }
1252
1253 /* Update the pg_class entry. */
1254 StorePartitionBound(rel, parent, bound);
1255
1256 table_close(parent, NoLock);
1257 }
1258
1259 /* Store inheritance information for new rel. */
1261
1262 /*
1263 * Process the partitioning specification (if any) and store the partition
1264 * key information into the catalog.
1265 */
1266 if (partitioned)
1267 {
1268 ParseState *pstate;
1269 int partnatts;
1270 AttrNumber partattrs[PARTITION_MAX_KEYS];
1272 Oid partcollation[PARTITION_MAX_KEYS];
1273 List *partexprs = NIL;
1274
1275 pstate = make_parsestate(NULL);
1276 pstate->p_sourcetext = queryString;
1277
1278 partnatts = list_length(stmt->partspec->partParams);
1279
1280 /* Protect fixed-size arrays here and in executor */
1281 if (partnatts > PARTITION_MAX_KEYS)
1282 ereport(ERROR,
1284 errmsg("cannot partition using more than %d columns",
1286
1287 /*
1288 * We need to transform the raw parsetrees corresponding to partition
1289 * expressions into executable expression trees. Like column defaults
1290 * and CHECK constraints, we could not have done the transformation
1291 * earlier.
1292 */
1293 stmt->partspec = transformPartitionSpec(rel, stmt->partspec);
1294
1295 ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
1296 partattrs, &partexprs, partopclass,
1297 partcollation, stmt->partspec->strategy);
1298
1299 StorePartitionKey(rel, stmt->partspec->strategy, partnatts, partattrs,
1300 partexprs,
1301 partopclass, partcollation);
1302
1303 /* make it all visible */
1305 }
1306
1307 /*
1308 * If we're creating a partition, create now all the indexes, triggers,
1309 * FKs defined in the parent.
1310 *
1311 * We can't do it earlier, because DefineIndex wants to know the partition
1312 * key which we just stored.
1313 */
1314 if (stmt->partbound)
1315 {
1317 Relation parent;
1318 List *idxlist;
1319 ListCell *cell;
1320
1321 /* Already have strong enough lock on the parent */
1322 parent = table_open(parentId, NoLock);
1323 idxlist = RelationGetIndexList(parent);
1324
1325 /*
1326 * For each index in the parent table, create one in the partition
1327 */
1328 foreach(cell, idxlist)
1329 {
1331 AttrMap *attmap;
1334
1335 if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1336 {
1337 if (idxRel->rd_index->indisunique)
1338 ereport(ERROR,
1340 errmsg("cannot create foreign partition of partitioned table \"%s\"",
1341 RelationGetRelationName(parent)),
1342 errdetail("Table \"%s\" contains indexes that are unique.",
1343 RelationGetRelationName(parent))));
1344 else
1345 {
1347 continue;
1348 }
1349 }
1350
1352 RelationGetDescr(parent),
1353 false);
1354 idxstmt =
1358 RelationGetRelid(rel),
1359 idxstmt,
1360 InvalidOid,
1363 -1,
1364 false, false, false, false, false);
1365
1367 }
1368
1370
1371 /*
1372 * If there are any row-level triggers, clone them to the new
1373 * partition.
1374 */
1375 if (parent->trigdesc != NULL)
1376 CloneRowTriggersToPartition(parent, rel);
1377
1378 /*
1379 * And foreign keys too. Note that because we're freshly creating the
1380 * table, there is no need to verify these new constraints.
1381 */
1382 CloneForeignKeyConstraints(NULL, parent, rel);
1383
1384 table_close(parent, NoLock);
1385 }
1386
1387 /*
1388 * Now add any newly specified CHECK constraints to the new relation. Same
1389 * as for defaults above, but these need to come after partitioning is set
1390 * up. We save the constraint names that were used, to avoid dupes below.
1391 */
1392 if (stmt->constraints)
1393 {
1394 List *conlist;
1395
1396 conlist = AddRelationNewConstraints(rel, NIL, stmt->constraints,
1397 true, true, false, queryString);
1399 {
1400 if (cons->name != NULL)
1401 connames = lappend(connames, cons->name);
1402 }
1403 }
1404
1405 /*
1406 * Finally, merge the not-null constraints that are declared directly with
1407 * those that come from parent relations (making sure to count inheritance
1408 * appropriately for each), create them, and set the attnotnull flag on
1409 * columns that don't yet have it.
1410 */
1411 nncols = AddRelationNotNullConstraints(rel, stmt->nnconstraints,
1413 foreach_int(attrnum, nncols)
1414 set_attnotnull(NULL, rel, attrnum, true, false);
1415
1417
1418 /*
1419 * Clean up. We keep lock on new relation (although it shouldn't be
1420 * visible to anyone else anyway, until commit).
1421 */
1422 relation_close(rel, NoLock);
1423
1424 return address;
1425}
Oid get_table_am_oid(const char *amname, bool missing_ok)
Definition amcmds.c:173
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition attmap.c:175
Oid GetDefaultTablespace(char relpersistence, bool partitioned)
#define palloc_object(type)
Definition fe_memutils.h:89
bool allowSystemTableMods
Definition globals.c:132
void StorePartitionKey(Relation rel, char strategy, int16 partnatts, AttrNumber *partattrs, List *partexprs, Oid *partopclass, Oid *partcollation)
Definition heap.c:3918
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:1140
List * AddRelationNotNullConstraints(Relation rel, List *constraints, List *old_notnulls, List *existing_constraints)
Definition heap.c:2917
void StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound)
Definition heap.c:4074
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition heap.c:2405
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:178
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:134
ObjectAddress DefineIndex(ParseState *pstate, Oid tableId, const IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, int total_parts, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition indexcmds.c:555
List * list_concat(List *list1, const List *list2)
Definition list.c:561
Oid get_rel_relam(Oid relid)
Definition lsyscache.c:2414
Oid get_rel_tablespace(Oid relid)
Definition lsyscache.c:2368
bool InSecurityRestrictedOperation(void)
Definition miscinit.c:640
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition namespace.h:98
ParseState * make_parsestate(ParseState *parentParseState)
Definition parse_node.c:39
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, LOCKMODE lockmode, Alias *alias, bool inh, bool inFromCl)
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition parse_type.c:291
PartitionBoundSpec * transformPartitionBound(ParseState *pstate, Relation parent, PartitionBoundSpec *spec)
IndexStmt * generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, const AttrMap *attmap, Oid *constraintOid)
@ CONSTR_DEFAULT
void check_new_partition_bound(char *relname, Relation parent, PartitionBoundSpec *spec, ParseState *pstate)
void check_default_partition_contents(Relation parent, Relation default_rel, PartitionBoundSpec *new_spec)
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition partdesc.c:71
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition partdesc.c:501
NameData relname
Definition pg_class.h:40
#define PARTITION_MAX_KEYS
#define NAMEDATALEN
#define foreach_ptr(type, var, lst)
Definition pg_list.h:501
#define linitial_oid(l)
Definition pg_list.h:180
#define foreach_int(var, lst)
Definition pg_list.h:502
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition strlcpy.c:45
@ ONCOMMIT_NOOP
Definition primnodes.h:59
bytea * view_reloptions(Datum reloptions, bool validate)
bytea * partitioned_table_reloptions(Datum reloptions, bool validate)
Datum transformRelOptions(Datum oldOptions, List *defList, const char *nameSpace, const char *const validnsps[], bool acceptOidsOff, bool isReset)
bytea * heap_reloptions(char relkind, Datum reloptions, bool validate)
#define HEAP_RELOPT_NAMESPACES
Definition reloptions.h:61
const char * p_sourcetext
Definition parse_node.h:214
TriggerDesc * trigdesc
Definition rel.h:117
char * default_table_access_method
Definition tableam.c:49
TupleDesc BuildDescForRelation(const List *columns)
Definition tablecmds.c:1437
static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, PartitionStrategy strategy)
static void CloneRowTriggersToPartition(Relation parent, Relation partition)
static void StoreCatalogInheritance(Oid relationId, List *supers, bool child_is_partition)
Definition tablecmds.c:3600
static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel, Relation partitionRel)
static PartitionSpec * transformPartitionSpec(Relation rel, PartitionSpec *partspec)
static void set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool is_valid, bool queue_validation)
Definition tablecmds.c:7981
static List * MergeAttributes(List *columns, const List *supers, char relpersistence, bool is_partition, List **supconstr, List **supnotnulls)
Definition tablecmds.c:2614
void CommandCounterIncrement(void)
Definition xact.c:1130

References AccessExclusiveLock, AccessShareLock, ACL_CREATE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, addNSItemToQuery(), addRangeTableEntryForRelation(), AddRelationNewConstraints(), AddRelationNotNullConstraints(), allowSystemTableMods, Assert, attnum, build_attrmap_by_name(), BuildDescForRelation(), check_default_partition_contents(), check_new_partition_bound(), CloneForeignKeyConstraints(), CloneRowTriggersToPartition(), CommandCounterIncrement(), ComputePartitionAttrs(), CONSTR_DEFAULT, default_table_access_method, DefineIndex(), elog, ereport, errcode(), errdetail(), errmsg, ERROR, fb(), foreach_int, foreach_ptr, generateClonedIndexStmt(), get_default_oid_from_partdesc(), get_rel_name(), get_rel_relam(), get_rel_tablespace(), get_table_am_oid(), get_tablespace_name(), get_tablespace_oid(), GetDefaultTablespace(), GetUserId(), heap_create_with_catalog(), HEAP_RELOPT_NAMESPACES, heap_reloptions(), index_close(), index_open(), InSecurityRestrictedOperation(), InvalidOid, lappend(), lappend_oid(), lfirst, lfirst_oid, linitial_oid, list_concat(), list_free(), list_length(), list_member_oid(), make_parsestate(), MergeAttributes(), MyDatabaseTableSpace, NAMEDATALEN, NIL, NoLock, object_aclcheck(), OBJECT_TABLESPACE, ObjectAddressSet, OidIsValid, ONCOMMIT_NOOP, ParseState::p_sourcetext, palloc_object, PARTITION_MAX_KEYS, partitioned_table_reloptions(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelid, RelationData::rd_rel, relation_close(), relation_open(), RelationGetDescr, RelationGetIndexList(), RelationGetPartitionDesc(), RelationGetRelationName, RelationGetRelid, relname, set_attnotnull(), ShareUpdateExclusiveLock, stmt, StoreCatalogInheritance(), StorePartitionBound(), StorePartitionKey(), strlcpy(), table_close(), table_open(), transformPartitionBound(), transformPartitionSpec(), transformRelOptions(), RelationData::trigdesc, TupleDescFinalize(), typenameTypeId(), and view_reloptions().

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

◆ ExecuteTruncate()

void ExecuteTruncate ( TruncateStmt stmt)
extern

Definition at line 1924 of file tablecmds.c.

1925{
1926 List *rels = NIL;
1927 List *relids = NIL;
1929 ListCell *cell;
1930
1931 /*
1932 * Open, exclusive-lock, and check all the explicitly-specified relations
1933 */
1934 foreach(cell, stmt->relations)
1935 {
1936 RangeVar *rv = lfirst(cell);
1937 Relation rel;
1938 bool recurse = rv->inh;
1939 Oid myrelid;
1940 LOCKMODE lockmode = AccessExclusiveLock;
1941
1942 myrelid = RangeVarGetRelidExtended(rv, lockmode,
1944 NULL);
1945
1946 /* don't throw error for "TRUNCATE foo, foo" */
1947 if (list_member_oid(relids, myrelid))
1948 continue;
1949
1950 /* open the relation, we already hold a lock on it */
1951 rel = table_open(myrelid, NoLock);
1952
1953 /*
1954 * RangeVarGetRelidExtended() has done most checks with its callback,
1955 * but other checks with the now-opened Relation remain.
1956 */
1958
1959 rels = lappend(rels, rel);
1960 relids = lappend_oid(relids, myrelid);
1961
1962 /* Log this relation only if needed for logical decoding */
1965
1966 if (recurse)
1967 {
1968 ListCell *child;
1969 List *children;
1970
1971 children = find_all_inheritors(myrelid, lockmode, NULL);
1972
1973 foreach(child, children)
1974 {
1975 Oid childrelid = lfirst_oid(child);
1976
1977 if (list_member_oid(relids, childrelid))
1978 continue;
1979
1980 /* find_all_inheritors already got lock */
1982
1983 /*
1984 * It is possible that the parent table has children that are
1985 * temp tables of other backends. We cannot safely access
1986 * such tables (because of buffering issues), and the best
1987 * thing to do is to silently ignore them. Note that this
1988 * check is the same as one of the checks done in
1989 * truncate_check_activity() called below, still it is kept
1990 * here for simplicity.
1991 */
1992 if (RELATION_IS_OTHER_TEMP(rel))
1993 {
1994 table_close(rel, lockmode);
1995 continue;
1996 }
1997
1998 /*
1999 * Inherited TRUNCATE commands perform access permission
2000 * checks on the parent table only. So we skip checking the
2001 * children's permissions and don't call
2002 * truncate_check_perms() here.
2003 */
2006
2007 rels = lappend(rels, rel);
2008 relids = lappend_oid(relids, childrelid);
2009
2010 /* Log this relation only if needed for logical decoding */
2013 }
2014 }
2015 else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2016 ereport(ERROR,
2018 errmsg("cannot truncate only a partitioned table"),
2019 errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
2020 }
2021
2022 ExecuteTruncateGuts(rels, relids, relids_logged,
2023 stmt->behavior, stmt->restart_seqs, false);
2024
2025 /* And close the rels */
2026 foreach(cell, rels)
2027 {
2028 Relation rel = (Relation) lfirst(cell);
2029
2030 table_close(rel, NoLock);
2031 }
2032}
struct RelationData * Relation
Definition genam.h:30
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
#define RelationIsLogicallyLogged(relation)
Definition rel.h:721
bool inh
Definition primnodes.h:87
static void truncate_check_activity(Relation rel)
Definition tablecmds.c:2506
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition tablecmds.c:2435
static void RangeVarCallbackForTruncate(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs, bool run_as_table_owner)
Definition tablecmds.c:2048

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

Referenced by standard_ProcessUtility().

◆ ExecuteTruncateGuts()

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

Definition at line 2048 of file tablecmds.c.

2053{
2054 List *rels;
2055 List *seq_relids = NIL;
2056 HTAB *ft_htab = NULL;
2057 EState *estate;
2059 ResultRelInfo *resultRelInfo;
2061 ListCell *cell;
2062 Oid *logrelids;
2063
2064 /*
2065 * Check the explicitly-specified relations.
2066 *
2067 * In CASCADE mode, suck in all referencing relations as well. This
2068 * requires multiple iterations to find indirectly-dependent relations. At
2069 * each phase, we need to exclusive-lock new rels before looking for their
2070 * dependencies, else we might miss something. Also, we check each rel as
2071 * soon as we open it, to avoid a faux pas such as holding lock for a long
2072 * time on a rel we have no permissions for.
2073 */
2074 rels = list_copy(explicit_rels);
2075 if (behavior == DROP_CASCADE)
2076 {
2077 for (;;)
2078 {
2079 List *newrelids;
2080
2082 if (newrelids == NIL)
2083 break; /* nothing else to add */
2084
2085 foreach(cell, newrelids)
2086 {
2087 Oid relid = lfirst_oid(cell);
2088 Relation rel;
2089
2090 rel = table_open(relid, AccessExclusiveLock);
2092 (errmsg("truncate cascades to table \"%s\"",
2094 truncate_check_rel(relid, rel->rd_rel);
2095 truncate_check_perms(relid, rel->rd_rel);
2097 rels = lappend(rels, rel);
2098 relids = lappend_oid(relids, relid);
2099
2100 /* Log this relation only if needed for logical decoding */
2103 }
2104 }
2105 }
2106
2107 /*
2108 * Check foreign key references. In CASCADE mode, this should be
2109 * unnecessary since we just pulled in all the references; but as a
2110 * cross-check, do it anyway if in an Assert-enabled build.
2111 */
2112#ifdef USE_ASSERT_CHECKING
2113 heap_truncate_check_FKs(rels, false);
2114#else
2115 if (behavior == DROP_RESTRICT)
2116 heap_truncate_check_FKs(rels, false);
2117#endif
2118
2119 /*
2120 * If we are asked to restart sequences, find all the sequences, lock them
2121 * (we need AccessExclusiveLock for ResetSequence), and check permissions.
2122 * We want to do this early since it's pointless to do all the truncation
2123 * work only to fail on sequence permissions.
2124 */
2125 if (restart_seqs)
2126 {
2127 foreach(cell, rels)
2128 {
2129 Relation rel = (Relation) lfirst(cell);
2132
2133 foreach(seqcell, seqlist)
2134 {
2137
2139
2140 /* This check must match AlterSequence! */
2144
2146
2148 }
2149 }
2150 }
2151
2152 /* Prepare to catch AFTER triggers. */
2154
2155 /*
2156 * To fire triggers, we'll need an EState as well as a ResultRelInfo for
2157 * each relation. We don't need to call ExecOpenIndices, though.
2158 *
2159 * We put the ResultRelInfos in the es_opened_result_relations list, even
2160 * though we don't have a range table and don't populate the
2161 * es_result_relations array. That's a bit bogus, but it's enough to make
2162 * ExecGetTriggerResultRel() find them.
2163 */
2164 estate = CreateExecutorState();
2166 palloc(list_length(rels) * sizeof(ResultRelInfo));
2167 resultRelInfo = resultRelInfos;
2168 foreach(cell, rels)
2169 {
2170 Relation rel = (Relation) lfirst(cell);
2171
2172 InitResultRelInfo(resultRelInfo,
2173 rel,
2174 0, /* dummy rangetable index */
2175 NULL,
2176 0);
2178 lappend(estate->es_opened_result_relations, resultRelInfo);
2179 resultRelInfo++;
2180 }
2181
2182 /*
2183 * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
2184 * truncating (this is because one of them might throw an error). Also, if
2185 * we were to allow them to prevent statement execution, that would need
2186 * to be handled here.
2187 */
2188 resultRelInfo = resultRelInfos;
2189 foreach(cell, rels)
2190 {
2192
2194 SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2195 &ucxt);
2196 ExecBSTruncateTriggers(estate, resultRelInfo);
2199 resultRelInfo++;
2200 }
2201
2202 /*
2203 * OK, truncate each table.
2204 */
2206
2207 foreach(cell, rels)
2208 {
2209 Relation rel = (Relation) lfirst(cell);
2210
2211 /* Skip partitioned tables as there is nothing to do */
2212 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2213 continue;
2214
2215 /*
2216 * Build the lists of foreign tables belonging to each foreign server
2217 * and pass each list to the foreign data wrapper's callback function,
2218 * so that each server can truncate its all foreign tables in bulk.
2219 * Each list is saved as a single entry in a hash table that uses the
2220 * server OID as lookup key.
2221 */
2222 if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2223 {
2225 bool found;
2227
2228 /* First time through, initialize hashtable for foreign tables */
2229 if (!ft_htab)
2230 {
2231 HASHCTL hctl;
2232
2233 memset(&hctl, 0, sizeof(HASHCTL));
2234 hctl.keysize = sizeof(Oid);
2235 hctl.entrysize = sizeof(ForeignTruncateInfo);
2237
2238 ft_htab = hash_create("TRUNCATE for Foreign Tables",
2239 32, /* start small and extend */
2240 &hctl,
2242 }
2243
2244 /* Find or create cached entry for the foreign table */
2245 ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
2246 if (!found)
2247 ft_info->rels = NIL;
2248
2249 /*
2250 * Save the foreign table in the entry of the server that the
2251 * foreign table belongs to.
2252 */
2253 ft_info->rels = lappend(ft_info->rels, rel);
2254 continue;
2255 }
2256
2257 /*
2258 * Normally, we need a transaction-safe truncation here. However, if
2259 * the table was either created in the current (sub)transaction or has
2260 * a new relfilenumber in the current (sub)transaction, then we can
2261 * just truncate it in-place, because a rollback would cause the whole
2262 * table or the current physical file to be thrown away anyway.
2263 */
2264 if (rel->rd_createSubid == mySubid ||
2266 {
2267 /* Immediate, non-rollbackable truncation is OK */
2269 }
2270 else
2271 {
2275
2276 /*
2277 * This effectively deletes all rows in the table, and may be done
2278 * in a serializable transaction. In that case we must record a
2279 * rw-conflict in to this transaction from each transaction
2280 * holding a predicate lock on the table.
2281 */
2283
2284 /*
2285 * Need the full transaction-safe pushups.
2286 *
2287 * Create a new empty storage file for the relation, and assign it
2288 * as the relfilenumber value. The old storage file is scheduled
2289 * for deletion at commit.
2290 */
2291 RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
2292
2294
2295 /*
2296 * The same for the toast table, if any.
2297 */
2298 toast_relid = rel->rd_rel->reltoastrelid;
2300 {
2303
2305 toastrel->rd_rel->relpersistence);
2307 }
2308
2309 /*
2310 * Reconstruct the indexes to match, and we're done.
2311 */
2314 }
2315
2317 }
2318
2319 /* Now go through the hash table, and truncate foreign tables */
2320 if (ft_htab)
2321 {
2324
2326
2327 PG_TRY();
2328 {
2329 while ((ft_info = hash_seq_search(&seq)) != NULL)
2330 {
2331 FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2332
2333 /* truncate_check_rel() has checked that already */
2334 Assert(routine->ExecForeignTruncate != NULL);
2335
2336 routine->ExecForeignTruncate(ft_info->rels,
2337 behavior,
2338 restart_seqs);
2339 }
2340 }
2341 PG_FINALLY();
2342 {
2344 }
2345 PG_END_TRY();
2346 }
2347
2348 /*
2349 * Restart owned sequences if we were asked to.
2350 */
2351 foreach(cell, seq_relids)
2352 {
2353 Oid seq_relid = lfirst_oid(cell);
2354
2356 }
2357
2358 /*
2359 * Write a WAL record to allow this set of actions to be logically
2360 * decoded.
2361 *
2362 * Assemble an array of relids so we can write a single WAL record for the
2363 * whole action.
2364 */
2365 if (relids_logged != NIL)
2366 {
2368 int i = 0;
2369
2370 /* should only get here if effective_wal_level is 'logical' */
2372
2374 foreach(cell, relids_logged)
2375 logrelids[i++] = lfirst_oid(cell);
2376
2377 xlrec.dbId = MyDatabaseId;
2378 xlrec.nrelids = list_length(relids_logged);
2379 xlrec.flags = 0;
2380 if (behavior == DROP_CASCADE)
2381 xlrec.flags |= XLH_TRUNCATE_CASCADE;
2382 if (restart_seqs)
2384
2388
2390
2392 }
2393
2394 /*
2395 * Process all AFTER STATEMENT TRUNCATE triggers.
2396 */
2397 resultRelInfo = resultRelInfos;
2398 foreach(cell, rels)
2399 {
2401
2403 SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2404 &ucxt);
2405 ExecASTruncateTriggers(estate, resultRelInfo);
2408 resultRelInfo++;
2409 }
2410
2411 /* Handle queued AFTER triggers */
2412 AfterTriggerEndQuery(estate);
2413
2414 /* We can clean up the EState now */
2415 FreeExecutorState(estate);
2416
2417 /*
2418 * Close any rels opened by CASCADE (can't do this while EState still
2419 * holds refs)
2420 */
2421 rels = list_difference_ptr(rels, explicit_rels);
2422 foreach(cell, rels)
2423 {
2424 Relation rel = (Relation) lfirst(cell);
2425
2426 table_close(rel, NoLock);
2427 }
2428}
uint32 SubTransactionId
Definition c.h:799
void ResetSequence(Oid seq_relid)
Definition sequence.c:255
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:889
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:360
void hash_destroy(HTAB *hashp)
Definition dynahash.c:802
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1352
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1317
#define PG_TRY(...)
Definition elog.h:374
#define PG_END_TRY(...)
Definition elog.h:399
#define PG_FINALLY(...)
Definition elog.h:391
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition execMain.c:1308
void FreeExecutorState(EState *estate)
Definition execUtils.c:197
EState * CreateExecutorState(void)
Definition execUtils.c:90
FdwRoutine * GetFdwRoutineByServerId(Oid serverid)
Definition foreign.c:409
Oid GetForeignServerIdByRelId(Oid relid)
Definition foreign.c:387
Oid MyDatabaseId
Definition globals.c:96
List * heap_truncate_find_FKs(List *relationIds)
Definition heap.c:3791
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition heap.c:3696
void heap_truncate_one_rel(Relation rel)
Definition heap.c:3652
#define XLOG_HEAP_TRUNCATE
Definition heapam_xlog.h:36
#define XLH_TRUNCATE_RESTART_SEQS
#define SizeOfHeapTruncate
#define XLH_TRUNCATE_CASCADE
@ HASH_ENTER
Definition hsearch.h:109
#define HASH_CONTEXT
Definition hsearch.h:97
#define HASH_ELEM
Definition hsearch.h:90
#define HASH_BLOBS
Definition hsearch.h:92
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition index.c:3981
#define REINDEX_REL_PROCESS_TOAST
Definition index.h:166
List * list_difference_ptr(const List *list1, const List *list2)
Definition list.c:1263
List * list_copy(const List *oldlist)
Definition list.c:1573
void * palloc(Size size)
Definition mcxt.c:1390
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
@ DROP_CASCADE
@ DROP_RESTRICT
@ OBJECT_SEQUENCE
List * getOwnedSequences(Oid relid)
Definition pg_depend.c:1140
void pgstat_count_truncate(Relation rel)
void CheckTableForSerializableConflictIn(Relation relation)
Definition predicate.c:4348
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition relcache.c:3779
List * es_opened_result_relations
Definition execnodes.h:725
ExecForeignTruncate_function ExecForeignTruncate
Definition fdwapi.h:268
Size keysize
Definition hsearch.h:69
Size entrysize
Definition hsearch.h:70
MemoryContext hcxt
Definition hsearch.h:81
SubTransactionId rd_newRelfilelocatorSubid
Definition rel.h:104
SubTransactionId rd_createSubid
Definition rel.h:103
Relation ri_RelationDesc
Definition execnodes.h:514
static void truncate_check_perms(Oid relid, Form_pg_class reltuple)
Definition tablecmds.c:2488
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition trigger.c:3307
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition trigger.c:3354
void AfterTriggerEndQuery(EState *estate)
Definition trigger.c:5186
void AfterTriggerBeginQuery(void)
Definition trigger.c:5166
void SwitchToUntrustedUser(Oid userid, UserContext *context)
Definition usercontext.c:33
void RestoreUserContext(UserContext *context)
Definition usercontext.c:87
SubTransactionId GetCurrentSubTransactionId(void)
Definition xact.c:793
#define XLogLogicalInfoActive()
Definition xlog.h:137
#define XLOG_INCLUDE_ORIGIN
Definition xlog.h:166
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition xloginsert.c:482
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:372
void XLogSetRecordFlags(uint8 flags)
Definition xloginsert.c:464
void XLogBeginInsert(void)
Definition xloginsert.c:153

References AccessExclusiveLock, aclcheck_error(), ACLCHECK_NOT_OWNER, AfterTriggerBeginQuery(), AfterTriggerEndQuery(), Assert, CheckTableForSerializableConflictIn(), CreateExecutorState(), CurrentMemoryContext, DROP_CASCADE, DROP_RESTRICT, HASHCTL::entrysize, ereport, errmsg, EState::es_opened_result_relations, ExecASTruncateTriggers(), ExecBSTruncateTriggers(), FdwRoutine::ExecForeignTruncate, fb(), FreeExecutorState(), GetCurrentSubTransactionId(), GetFdwRoutineByServerId(), GetForeignServerIdByRelId(), getOwnedSequences(), GetUserId(), HASH_BLOBS, HASH_CONTEXT, hash_create(), hash_destroy(), HASH_ELEM, HASH_ENTER, hash_search(), hash_seq_init(), hash_seq_search(), HASHCTL::hcxt, heap_truncate_check_FKs(), heap_truncate_find_FKs(), heap_truncate_one_rel(), i, InitResultRelInfo(), HASHCTL::keysize, lappend(), lappend_oid(), lfirst, lfirst_oid, list_copy(), list_difference_ptr(), list_length(), MyDatabaseId, NIL, NoLock, NOTICE, object_ownercheck(), OBJECT_SEQUENCE, OidIsValid, palloc(), PG_END_TRY, PG_FINALLY, PG_TRY, pgstat_count_truncate(), RelationData::rd_createSubid, RelationData::rd_newRelfilelocatorSubid, RelationData::rd_rel, REINDEX_REL_PROCESS_TOAST, reindex_relation(), relation_close(), relation_open(), RelationGetRelationName, RelationGetRelid, RelationIsLogicallyLogged, RelationSetNewRelfilenumber(), ResetSequence(), RestoreUserContext(), ResultRelInfo::ri_RelationDesc, SizeOfHeapTruncate, SwitchToUntrustedUser(), table_close(), table_open(), truncate_check_activity(), truncate_check_perms(), truncate_check_rel(), XLH_TRUNCATE_CASCADE, XLH_TRUNCATE_RESTART_SEQS, XLOG_HEAP_TRUNCATE, XLOG_INCLUDE_ORIGIN, XLogBeginInsert(), XLogInsert(), XLogLogicalInfoActive, XLogRegisterData(), and XLogSetRecordFlags().

Referenced by apply_handle_truncate(), and ExecuteTruncate().

◆ find_composite_type_dependencies()

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

Definition at line 7077 of file tablecmds.c.

7079{
7081 ScanKeyData key[2];
7084
7085 /* since this function recurses, it could be driven to stack overflow */
7087
7088 /*
7089 * We scan pg_depend to find those things that depend on the given type.
7090 * (We assume we can ignore refobjsubid for a type.)
7091 */
7093
7094 ScanKeyInit(&key[0],
7098 ScanKeyInit(&key[1],
7101 ObjectIdGetDatum(typeOid));
7102
7104 NULL, 2, key);
7105
7107 {
7109 Relation rel;
7112
7113 /* Check for directly dependent types */
7114 if (pg_depend->classid == TypeRelationId)
7115 {
7116 /*
7117 * This must be an array, domain, or range containing the given
7118 * type, so recursively check for uses of this type. Note that
7119 * any error message will mention the original type not the
7120 * container; this is intentional.
7121 */
7124 continue;
7125 }
7126
7127 /* Else, ignore dependees that aren't relations */
7128 if (pg_depend->classid != RelationRelationId)
7129 continue;
7130
7133
7134 /*
7135 * If objsubid identifies a specific column, refer to that in error
7136 * messages. Otherwise, search to see if there's a user column of the
7137 * type. (We assume system columns are never of interesting types.)
7138 * The search is needed because an index containing an expression
7139 * column of the target type will just be recorded as a whole-relation
7140 * dependency. If we do not find a column of the type, the dependency
7141 * must indicate that the type is transiently referenced in an index
7142 * expression but not stored on disk, which we assume is OK, just as
7143 * we do for references in views. (It could also be that the target
7144 * type is embedded in some container type that is stored in an index
7145 * column, but the previous recursion should catch such cases.)
7146 */
7147 if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
7148 att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
7149 else
7150 {
7151 att = NULL;
7152 for (int attno = 1; attno <= tupleDesc->natts; attno++)
7153 {
7154 att = TupleDescAttr(tupleDesc, attno - 1);
7155 if (att->atttypid == typeOid && !att->attisdropped)
7156 break;
7157 att = NULL;
7158 }
7159 if (att == NULL)
7160 {
7161 /* No such column, so assume OK */
7163 continue;
7164 }
7165 }
7166
7167 /*
7168 * We definitely should reject if the relation has storage. If it's
7169 * partitioned, then perhaps we don't have to reject: if there are
7170 * partitions then we'll fail when we find one, else there is no
7171 * stored data to worry about. However, it's possible that the type
7172 * change would affect conclusions about whether the type is sortable
7173 * or hashable and thus (if it's a partitioning column) break the
7174 * partitioning rule. For now, reject for partitioned rels too.
7175 */
7176 if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
7177 RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
7178 {
7179 if (origTypeName)
7180 ereport(ERROR,
7182 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
7185 NameStr(att->attname))));
7186 else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
7187 ereport(ERROR,
7189 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
7192 NameStr(att->attname))));
7193 else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
7194 ereport(ERROR,
7196 errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
7199 NameStr(att->attname))));
7200 else
7201 ereport(ERROR,
7203 errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
7206 NameStr(att->attname))));
7207 }
7208 else if (OidIsValid(rel->rd_rel->reltype))
7209 {
7210 /*
7211 * A view or composite type itself isn't a problem, but we must
7212 * recursively check for indirect dependencies via its rowtype.
7213 */
7216 }
7217
7219 }
7220
7222
7224}
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
END_CATALOG_STRUCT typedef FormData_pg_depend * Form_pg_depend
Definition pg_depend.h:76
void check_stack_depth(void)
Definition stack_depth.c:96
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition tablecmds.c:7077

References AccessShareLock, BTEqualStrategyNumber, check_stack_depth(), ereport, errcode(), errmsg, ERROR, fb(), find_composite_type_dependencies(), Form_pg_depend, GETSTRUCT(), HeapTupleIsValid, NameStr, ObjectIdGetDatum(), OidIsValid, RelationData::rd_rel, relation_close(), relation_open(), RelationGetDescr, RelationGetRelationName, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_open(), and TupleDescAttr().

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

◆ PartConstraintImpliedByRelConstraint()

bool PartConstraintImpliedByRelConstraint ( Relation  scanrel,
List partConstraint 
)
extern

Definition at line 20791 of file tablecmds.c.

20793{
20795 TupleConstr *constr = RelationGetDescr(scanrel)->constr;
20796 int i;
20797
20798 if (constr && constr->has_not_null)
20799 {
20800 int natts = scanrel->rd_att->natts;
20801
20802 for (i = 1; i <= natts; i++)
20803 {
20804 CompactAttribute *att = TupleDescCompactAttr(scanrel->rd_att, i - 1);
20805
20806 /* invalid not-null constraint must be ignored here */
20807 if (att->attnullability == ATTNULLABLE_VALID && !att->attisdropped)
20808 {
20811
20812 ntest->arg = (Expr *) makeVar(1,
20813 i,
20814 wholeatt->atttypid,
20815 wholeatt->atttypmod,
20816 wholeatt->attcollation,
20817 0);
20818 ntest->nulltesttype = IS_NOT_NULL;
20819
20820 /*
20821 * argisrow=false is correct even for a composite column,
20822 * because attnotnull does not represent a SQL-spec IS NOT
20823 * NULL test in such a case, just IS DISTINCT FROM NULL.
20824 */
20825 ntest->argisrow = false;
20826 ntest->location = -1;
20828 }
20829 }
20830 }
20831
20833}
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition makefuncs.c:66
@ IS_NOT_NULL
Definition primnodes.h:1975
bool attisdropped
Definition tupdesc.h:78
char attnullability
Definition tupdesc.h:80
TupleDesc rd_att
Definition rel.h:112
bool has_not_null
Definition tupdesc.h:45
ParseLoc location
Definition primnodes.h:311
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
#define ATTNULLABLE_VALID
Definition tupdesc.h:86
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:195

References CompactAttribute::attisdropped, CompactAttribute::attnullability, ATTNULLABLE_VALID, ConstraintImpliedByRelConstraint(), fb(), TupleConstr::has_not_null, i, IS_NOT_NULL, lappend(), Var::location, makeNode, makeVar(), TupleDescData::natts, NIL, RelationData::rd_att, RelationGetDescr, TupleDescAttr(), and TupleDescCompactAttr().

Referenced by check_default_partition_contents(), and QueuePartitionConstraintValidation().

◆ PreCommit_on_commit_actions()

void PreCommit_on_commit_actions ( void  )
extern

Definition at line 20023 of file tablecmds.c.

20024{
20025 ListCell *l;
20028
20029 foreach(l, on_commits)
20030 {
20032
20033 /* Ignore entry if already dropped in this xact */
20034 if (oc->deleting_subid != InvalidSubTransactionId)
20035 continue;
20036
20037 switch (oc->oncommit)
20038 {
20039 case ONCOMMIT_NOOP:
20041 /* Do nothing (there shouldn't be such entries, actually) */
20042 break;
20044
20045 /*
20046 * If this transaction hasn't accessed any temporary
20047 * relations, we can skip truncating ON COMMIT DELETE ROWS
20048 * tables, as they must still be empty.
20049 */
20052 break;
20053 case ONCOMMIT_DROP:
20055 break;
20056 }
20057 }
20058
20059 /*
20060 * Truncate relations before dropping so that all dependencies between
20061 * relations are removed after they are worked on. Doing it like this
20062 * might be a waste as it is possible that a relation being truncated will
20063 * be dropped anyway due to its parent being dropped, but this makes the
20064 * code more robust because of not having to re-check that the relation
20065 * exists at truncation time.
20066 */
20067 if (oids_to_truncate != NIL)
20069
20070 if (oids_to_drop != NIL)
20071 {
20073
20074 foreach(l, oids_to_drop)
20075 {
20076 ObjectAddress object;
20077
20078 object.classId = RelationRelationId;
20079 object.objectId = lfirst_oid(l);
20080 object.objectSubId = 0;
20081
20083
20085 }
20086
20087 /*
20088 * Object deletion might involve toast table access (to clean up
20089 * toasted catalog entries), so ensure we have a valid snapshot.
20090 */
20092
20093 /*
20094 * Since this is an automatic drop, rather than one directly initiated
20095 * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
20096 */
20099
20101
20102#ifdef USE_ASSERT_CHECKING
20103
20104 /*
20105 * Note that table deletion will call remove_on_commit_action, so the
20106 * entry should get marked as deleted.
20107 */
20108 foreach(l, on_commits)
20109 {
20111
20112 if (oc->oncommit != ONCOMMIT_DROP)
20113 continue;
20114
20115 Assert(oc->deleting_subid != InvalidSubTransactionId);
20116 }
20117#endif
20118 }
20119}
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition dependency.c:388
#define PERFORM_DELETION_QUIETLY
Definition dependency.h:94
#define PERFORM_DELETION_INTERNAL
Definition dependency.h:92
void heap_truncate(List *relids)
Definition heap.c:3611
@ ONCOMMIT_DELETE_ROWS
Definition primnodes.h:61
@ ONCOMMIT_PRESERVE_ROWS
Definition primnodes.h:60
@ ONCOMMIT_DROP
Definition primnodes.h:62
Snapshot GetTransactionSnapshot(void)
Definition snapmgr.c:272
void PushActiveSnapshot(Snapshot snapshot)
Definition snapmgr.c:682
void PopActiveSnapshot(void)
Definition snapmgr.c:775
int MyXactFlags
Definition xact.c:138
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition xact.h:103

References add_exact_object_address(), Assert, ObjectAddress::classId, DROP_CASCADE, fb(), GetTransactionSnapshot(), heap_truncate(), InvalidSubTransactionId, lappend_oid(), lfirst, lfirst_oid, MyXactFlags, new_object_addresses(), NIL, object_address_present(), on_commits, ONCOMMIT_DELETE_ROWS, ONCOMMIT_DROP, ONCOMMIT_NOOP, ONCOMMIT_PRESERVE_ROWS, PERFORM_DELETION_INTERNAL, PERFORM_DELETION_QUIETLY, performMultipleDeletions(), PopActiveSnapshot(), PushActiveSnapshot(), and XACT_FLAGS_ACCESSEDTEMPNAMESPACE.

Referenced by CommitTransaction(), and PrepareTransaction().

◆ RangeVarCallbackMaintainsTable()

void RangeVarCallbackMaintainsTable ( const RangeVar relation,
Oid  relId,
Oid  oldRelId,
void arg 
)
extern

Definition at line 20197 of file tablecmds.c.

20199{
20200 char relkind;
20202
20203 /* Nothing to do if the relation was not found. */
20204 if (!OidIsValid(relId))
20205 return;
20206
20207 /*
20208 * If the relation does exist, check whether it's an index. But note that
20209 * the relation might have been dropped between the time we did the name
20210 * lookup and now. In that case, there's nothing to do.
20211 */
20212 relkind = get_rel_relkind(relId);
20213 if (!relkind)
20214 return;
20215 if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
20216 relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
20217 ereport(ERROR,
20219 errmsg("\"%s\" is not a table or materialized view", relation->relname)));
20220
20221 /* Check permissions */
20223 if (aclresult != ACLCHECK_OK)
20226 relation->relname);
20227}
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition aclchk.c:4105
#define ACL_MAINTAIN
Definition parsenodes.h:90
char * relname
Definition primnodes.h:84

References ACL_MAINTAIN, aclcheck_error(), ACLCHECK_OK, ereport, errcode(), errmsg, ERROR, fb(), get_rel_relkind(), get_relkind_objtype(), GetUserId(), OidIsValid, pg_class_aclcheck(), and RangeVar::relname.

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

◆ RangeVarCallbackOwnsRelation()

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

Definition at line 20257 of file tablecmds.c.

20259{
20260 HeapTuple tuple;
20261
20262 /* Nothing to do if the relation was not found. */
20263 if (!OidIsValid(relId))
20264 return;
20265
20266 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
20267 if (!HeapTupleIsValid(tuple)) /* should not happen */
20268 elog(ERROR, "cache lookup failed for relation %u", relId);
20269
20272 relation->relname);
20273
20274 /*
20275 * Conflict log tables are used internally for logical replication
20276 * conflict logging and should not be modified directly, as it could
20277 * disrupt conflict logging.
20278 */
20280 ereport(ERROR,
20282 errmsg("cannot change conflict log table \"%s\"",
20283 relation->relname),
20284 errdetail("Conflict log tables are system-managed tables for logical replication conflicts.")));
20285
20286 if (!allowSystemTableMods &&
20287 IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
20288 ereport(ERROR,
20290 errmsg("permission denied: \"%s\" is a system catalog",
20291 relation->relname)));
20292
20293 ReleaseSysCache(tuple);
20294}
bool IsConflictLogTableClass(Form_pg_class reltuple)
Definition catalog.c:242
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition catalog.c:86

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

Referenced by AlterPropGraph(), AlterSequence(), CreatePropGraph(), ProcessUtilitySlow(), transformPartitionCmdForMerge(), and transformPartitionCmdForSplit().

◆ register_on_commit_action()

void register_on_commit_action ( Oid  relid,
OnCommitAction  action 
)
extern

Definition at line 19964 of file tablecmds.c.

19965{
19968
19969 /*
19970 * We needn't bother registering the relation unless there is an ON COMMIT
19971 * action we need to take.
19972 */
19973 if (action == ONCOMMIT_NOOP || action == ONCOMMIT_PRESERVE_ROWS)
19974 return;
19975
19977
19979 oc->relid = relid;
19980 oc->oncommit = action;
19981 oc->creating_subid = GetCurrentSubTransactionId();
19982 oc->deleting_subid = InvalidSubTransactionId;
19983
19984 /*
19985 * We use lcons() here so that ON COMMIT actions are processed in reverse
19986 * order of registration. That might not be essential but it seems
19987 * reasonable.
19988 */
19990
19992}
List * lcons(void *datum, List *list)
Definition list.c:495
MemoryContext CacheMemoryContext
Definition mcxt.c:170
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138

References CacheMemoryContext, fb(), GetCurrentSubTransactionId(), InvalidSubTransactionId, lcons(), MemoryContextSwitchTo(), on_commits, ONCOMMIT_NOOP, ONCOMMIT_PRESERVE_ROWS, and palloc_object.

Referenced by heap_create_with_catalog().

◆ remove_on_commit_action()

void remove_on_commit_action ( Oid  relid)
extern

Definition at line 20000 of file tablecmds.c.

20001{
20002 ListCell *l;
20003
20004 foreach(l, on_commits)
20005 {
20007
20008 if (oc->relid == relid)
20009 {
20011 break;
20012 }
20013 }
20014}
SubTransactionId deleting_subid
Definition tablecmds.c:132

References OnCommitItem::deleting_subid, fb(), GetCurrentSubTransactionId(), lfirst, and on_commits.

Referenced by heap_drop_with_catalog().

◆ RemoveRelations()

void RemoveRelations ( DropStmt drop)
extern

Definition at line 1597 of file tablecmds.c.

1598{
1599 ObjectAddresses *objects;
1600 char relkind;
1601 ListCell *cell;
1602 int flags = 0;
1603 LOCKMODE lockmode = AccessExclusiveLock;
1604
1605 /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1606 if (drop->concurrent)
1607 {
1608 /*
1609 * Note that for temporary relations this lock may get upgraded later
1610 * on, but as no other session can access a temporary relation, this
1611 * is actually fine.
1612 */
1613 lockmode = ShareUpdateExclusiveLock;
1614 Assert(drop->removeType == OBJECT_INDEX);
1615 if (list_length(drop->objects) != 1)
1616 ereport(ERROR,
1618 errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1619 if (drop->behavior == DROP_CASCADE)
1620 ereport(ERROR,
1622 errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1623 }
1624
1625 /*
1626 * First we identify all the relations, then we delete them in a single
1627 * performMultipleDeletions() call. This is to avoid unwanted DROP
1628 * RESTRICT errors if one of the relations depends on another.
1629 */
1630
1631 /* Determine required relkind */
1632 switch (drop->removeType)
1633 {
1634 case OBJECT_TABLE:
1635 relkind = RELKIND_RELATION;
1636 break;
1637
1638 case OBJECT_INDEX:
1639 relkind = RELKIND_INDEX;
1640 break;
1641
1642 case OBJECT_SEQUENCE:
1643 relkind = RELKIND_SEQUENCE;
1644 break;
1645
1646 case OBJECT_VIEW:
1647 relkind = RELKIND_VIEW;
1648 break;
1649
1650 case OBJECT_MATVIEW:
1651 relkind = RELKIND_MATVIEW;
1652 break;
1653
1655 relkind = RELKIND_FOREIGN_TABLE;
1656 break;
1657
1658 case OBJECT_PROPGRAPH:
1659 relkind = RELKIND_PROPGRAPH;
1660 break;
1661
1662 default:
1663 elog(ERROR, "unrecognized drop object type: %d",
1664 (int) drop->removeType);
1665 relkind = 0; /* keep compiler quiet */
1666 break;
1667 }
1668
1669 /* Lock and validate each relation; build a list of object addresses */
1670 objects = new_object_addresses();
1671
1672 foreach(cell, drop->objects)
1673 {
1674 RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1675 Oid relOid;
1676 ObjectAddress obj;
1678
1679 /*
1680 * These next few steps are a great deal like relation_openrv, but we
1681 * don't bother building a relcache entry since we don't need it.
1682 *
1683 * Check for shared-cache-inval messages before trying to access the
1684 * relation. This is needed to cover the case where the name
1685 * identifies a rel that has been dropped and recreated since the
1686 * start of our transaction: if we don't flush the old syscache entry,
1687 * then we'll latch onto that entry and suffer an error later.
1688 */
1690
1691 /* Look up the appropriate relation using namespace search. */
1692 state.expected_relkind = relkind;
1693 state.heap_lockmode = drop->concurrent ?
1695 /* We must initialize these fields to show that no locks are held: */
1696 state.heapOid = InvalidOid;
1697 state.partParentOid = InvalidOid;
1698
1699 relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1701 &state);
1702
1703 /* Not there? */
1704 if (!OidIsValid(relOid))
1705 {
1706 DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1707 continue;
1708 }
1709
1710 /*
1711 * Decide if concurrent mode needs to be used here or not. The
1712 * callback retrieved the rel's persistence for us.
1713 */
1714 if (drop->concurrent &&
1715 state.actual_relpersistence != RELPERSISTENCE_TEMP)
1716 {
1717 Assert(list_length(drop->objects) == 1 &&
1718 drop->removeType == OBJECT_INDEX);
1720 }
1721
1722 /*
1723 * Concurrent index drop cannot be used with partitioned indexes,
1724 * either.
1725 */
1726 if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1727 state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1728 ereport(ERROR,
1730 errmsg("cannot drop partitioned index \"%s\" concurrently",
1731 rel->relname)));
1732
1733 /*
1734 * If we're told to drop a partitioned index, we must acquire lock on
1735 * all the children of its parent partitioned table before proceeding.
1736 * Otherwise we'd try to lock the child index partitions before their
1737 * tables, leading to potential deadlock against other sessions that
1738 * will lock those objects in the other order.
1739 */
1740 if (state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1741 (void) find_all_inheritors(state.heapOid,
1742 state.heap_lockmode,
1743 NULL);
1744
1745 /* OK, we're ready to delete this one */
1747 obj.objectId = relOid;
1748 obj.objectSubId = 0;
1749
1750 add_exact_object_address(&obj, objects);
1751 }
1752
1753 performMultipleDeletions(objects, drop->behavior, flags);
1754
1755 free_object_addresses(objects);
1756}
#define PERFORM_DELETION_CONCURRENTLY
Definition dependency.h:93
void AcceptInvalidationMessages(void)
Definition inval.c:930
RangeVar * makeRangeVarFromNameList(const List *names)
Definition namespace.c:3626
@ OBJECT_PROPGRAPH
@ OBJECT_FOREIGN_TABLE
@ OBJECT_VIEW
static void DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
Definition tablecmds.c:1522
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
Definition tablecmds.c:1765

References AcceptInvalidationMessages(), AccessExclusiveLock, add_exact_object_address(), Assert, ObjectAddress::classId, DROP_CASCADE, DropErrorMsgNonExistent(), elog, ereport, errcode(), errmsg, ERROR, fb(), find_all_inheritors(), free_object_addresses(), InvalidOid, lfirst, list_length(), makeRangeVarFromNameList(), new_object_addresses(), OBJECT_FOREIGN_TABLE, OBJECT_INDEX, OBJECT_MATVIEW, OBJECT_PROPGRAPH, OBJECT_SEQUENCE, OBJECT_TABLE, OBJECT_VIEW, ObjectAddress::objectId, ObjectAddress::objectSubId, OidIsValid, PERFORM_DELETION_CONCURRENTLY, performMultipleDeletions(), RangeVarCallbackForDropRelation(), RangeVarGetRelidExtended(), RangeVar::relname, RVR_MISSING_OK, and ShareUpdateExclusiveLock.

Referenced by ExecDropStmt().

◆ renameatt()

ObjectAddress renameatt ( RenameStmt stmt)
extern

Definition at line 4101 of file tablecmds.c.

4102{
4103 Oid relid;
4105 ObjectAddress address;
4106
4107 /* lock level taken here should match renameatt_internal */
4109 stmt->missing_ok ? RVR_MISSING_OK : 0,
4111 NULL);
4112
4113 if (!OidIsValid(relid))
4114 {
4116 (errmsg("relation \"%s\" does not exist, skipping",
4117 stmt->relation->relname)));
4118 return InvalidObjectAddress;
4119 }
4120
4121 attnum =
4122 renameatt_internal(relid,
4123 stmt->subname, /* old att name */
4124 stmt->newname, /* new att name */
4125 stmt->relation->inh, /* recursive? */
4126 false, /* recursing? */
4127 0, /* expected inhcount */
4128 stmt->behavior);
4129
4131
4132 return address;
4133}
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition tablecmds.c:3936
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition tablecmds.c:4081

References AccessExclusiveLock, attnum, ereport, errmsg, fb(), InvalidObjectAddress, NOTICE, ObjectAddressSubSet, OidIsValid, RangeVarCallbackForRenameAttribute(), RangeVarGetRelidExtended(), renameatt_internal(), RVR_MISSING_OK, and stmt.

Referenced by ExecRenameStmt().

◆ RenameConstraint()

ObjectAddress RenameConstraint ( RenameStmt stmt)
extern

Definition at line 4248 of file tablecmds.c.

4249{
4250 Oid relid = InvalidOid;
4251 Oid typid = InvalidOid;
4252
4253 if (stmt->renameType == OBJECT_DOMCONSTRAINT)
4254 {
4255 Relation rel;
4256 HeapTuple tup;
4257
4261 if (!HeapTupleIsValid(tup))
4262 elog(ERROR, "cache lookup failed for type %u", typid);
4265 table_close(rel, NoLock);
4266 }
4267 else
4268 {
4269 /* lock level taken here should match rename_constraint_internal */
4271 stmt->missing_ok ? RVR_MISSING_OK : 0,
4273 NULL);
4274 if (!OidIsValid(relid))
4275 {
4277 (errmsg("relation \"%s\" does not exist, skipping",
4278 stmt->relation->relname)));
4279 return InvalidObjectAddress;
4280 }
4281 }
4282
4283 return
4284 rename_constraint_internal(relid, typid,
4285 stmt->subname,
4286 stmt->newname,
4287 (stmt->relation &&
4288 stmt->relation->inh), /* recursive? */
4289 false, /* recursing? */
4290 0 /* expected inhcount */ );
4291}
TypeName * makeTypeNameFromNameList(List *names)
Definition makefuncs.c:531
#define castNode(_type_, nodeptr)
Definition nodes.h:180
@ OBJECT_DOMCONSTRAINT
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:4139
void checkDomainOwner(HeapTuple tup)
Definition typecmds.c:3525

References AccessExclusiveLock, castNode, checkDomainOwner(), elog, ereport, errmsg, ERROR, fb(), HeapTupleIsValid, InvalidObjectAddress, InvalidOid, makeTypeNameFromNameList(), NoLock, NOTICE, OBJECT_DOMCONSTRAINT, ObjectIdGetDatum(), OidIsValid, RangeVarCallbackForRenameAttribute(), RangeVarGetRelidExtended(), ReleaseSysCache(), rename_constraint_internal(), RowExclusiveLock, RVR_MISSING_OK, SearchSysCache1(), stmt, table_close(), table_open(), and typenameTypeId().

Referenced by ExecRenameStmt().

◆ RenameRelation()

ObjectAddress RenameRelation ( RenameStmt stmt)
extern

Definition at line 4298 of file tablecmds.c.

4299{
4300 bool is_index_stmt = stmt->renameType == OBJECT_INDEX;
4301 Oid relid;
4302 ObjectAddress address;
4303
4304 /*
4305 * Grab an exclusive lock on the target table, index, sequence, view,
4306 * materialized view, or foreign table, which we will NOT release until
4307 * end of transaction.
4308 *
4309 * Lock level used here should match RenameRelationInternal, to avoid lock
4310 * escalation. However, because ALTER INDEX can be used with any relation
4311 * type, we mustn't believe without verification.
4312 */
4313 for (;;)
4314 {
4315 LOCKMODE lockmode;
4316 char relkind;
4317 bool obj_is_index;
4318
4320
4321 relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
4322 stmt->missing_ok ? RVR_MISSING_OK : 0,
4324 stmt);
4325
4326 if (!OidIsValid(relid))
4327 {
4329 (errmsg("relation \"%s\" does not exist, skipping",
4330 stmt->relation->relname)));
4331 return InvalidObjectAddress;
4332 }
4333
4334 /*
4335 * We allow mismatched statement and object types (e.g., ALTER INDEX
4336 * to rename a table), but we might've used the wrong lock level. If
4337 * that happens, retry with the correct lock level. We don't bother
4338 * if we already acquired AccessExclusiveLock with an index, however.
4339 */
4340 relkind = get_rel_relkind(relid);
4341 obj_is_index = (relkind == RELKIND_INDEX ||
4342 relkind == RELKIND_PARTITIONED_INDEX);
4344 break;
4345
4346 UnlockRelationOid(relid, lockmode);
4348 }
4349
4350 /* Do the work */
4351 RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
4352
4353 ObjectAddressSet(address, RelationRelationId, relid);
4354
4355 return address;
4356}
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition lmgr.c:229
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition tablecmds.c:4362

References AccessExclusiveLock, ereport, errmsg, fb(), get_rel_relkind(), InvalidObjectAddress, NOTICE, OBJECT_INDEX, ObjectAddressSet, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetRelidExtended(), RenameRelationInternal(), RVR_MISSING_OK, ShareUpdateExclusiveLock, stmt, and UnlockRelationOid().

Referenced by ExecRenameStmt().

◆ RenameRelationInternal()

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

Definition at line 4362 of file tablecmds.c.

4363{
4365 Relation relrelation; /* for RELATION relation */
4370
4371 /*
4372 * Grab a lock on the target relation, which we will NOT release until end
4373 * of transaction. We need at least a self-exclusive lock so that
4374 * concurrent DDL doesn't overwrite the rename if they start updating
4375 * while still seeing the old version. The lock also guards against
4376 * triggering relcache reloads in concurrent sessions, which might not
4377 * handle this information changing under them. For indexes, we can use a
4378 * reduced lock level because RelationReloadIndexInfo() handles indexes
4379 * specially.
4380 */
4383
4384 /*
4385 * Find relation's pg_class tuple, and make sure newrelname isn't in use.
4386 */
4388
4390 if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4391 elog(ERROR, "cache lookup failed for relation %u", myrelid);
4392 otid = reltup->t_self;
4394
4396 ereport(ERROR,
4398 errmsg("relation \"%s\" already exists",
4399 newrelname)));
4400
4401 /*
4402 * RenameRelation is careful not to believe the caller's idea of the
4403 * relation kind being handled. We don't have to worry about this, but
4404 * let's not be totally oblivious to it. We can process an index as
4405 * not-an-index, but not the other way around.
4406 */
4407 Assert(!is_index ||
4408 is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4409 targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
4410
4411 /*
4412 * Update pg_class tuple with new relname. (Scribbling on reltup is OK
4413 * because it's a copy...)
4414 */
4415 namestrcpy(&(relform->relname), newrelname);
4416
4419
4421 InvalidOid, is_internal);
4422
4425
4426 /*
4427 * Also rename the associated type, if any.
4428 */
4429 if (OidIsValid(targetrelation->rd_rel->reltype))
4430 RenameTypeInternal(targetrelation->rd_rel->reltype,
4432
4433 /*
4434 * Also rename the associated constraint, if any.
4435 */
4436 if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4437 targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4438 {
4440
4443 }
4444
4445 /*
4446 * Close rel, but keep lock!
4447 */
4449}
void namestrcpy(Name name, const char *str)
Definition name.c:233
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
void RenameConstraintById(Oid conId, const char *newname)
Oid get_index_constraint(Oid indexId)
Definition pg_depend.c:1192
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition pg_type.c:763

References AccessExclusiveLock, Assert, CatalogTupleUpdate(), elog, ereport, errcode(), errmsg, ERROR, fb(), get_index_constraint(), get_relname_relid(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, InplaceUpdateTupleLock, InvalidOid, InvokeObjectPostAlterHookArg, namestrcpy(), NoLock, ObjectIdGetDatum(), OidIsValid, relation_close(), relation_open(), RelationGetNamespace, RenameConstraintById(), RenameTypeInternal(), RowExclusiveLock, SearchSysCacheLockedCopy1(), ShareUpdateExclusiveLock, table_close(), table_open(), and UnlockTuple().

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

◆ ResetRelRewrite()

void ResetRelRewrite ( Oid  myrelid)
extern

Definition at line 4455 of file tablecmds.c.

4456{
4457 Relation relrelation; /* for RELATION relation */
4460
4461 /*
4462 * Find relation's pg_class tuple.
4463 */
4465
4467 if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4468 elog(ERROR, "cache lookup failed for relation %u", myrelid);
4470
4471 /*
4472 * Update pg_class tuple.
4473 */
4474 relform->relrewrite = InvalidOid;
4475
4477
4480}
#define SearchSysCacheCopy1(cacheId, key1)
Definition syscache.h:91

References CatalogTupleUpdate(), elog, ERROR, fb(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by finish_heap_swap().

◆ SetRelationHasSubclass()

void SetRelationHasSubclass ( Oid  relationId,
bool  relhassubclass 
)
extern

Definition at line 3726 of file tablecmds.c.

3727{
3729 HeapTuple tuple;
3731
3733 ShareUpdateExclusiveLock, false) ||
3735 ShareRowExclusiveLock, true));
3736
3737 /*
3738 * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3739 */
3742 if (!HeapTupleIsValid(tuple))
3743 elog(ERROR, "cache lookup failed for relation %u", relationId);
3745
3746 if (classtuple->relhassubclass != relhassubclass)
3747 {
3748 classtuple->relhassubclass = relhassubclass;
3750 }
3751 else
3752 {
3753 /* no need to change tuple, but force relcache rebuild anyway */
3755 }
3756
3757 heap_freetuple(tuple);
3759}
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition inval.c:1666
bool CheckRelationOidLockedByMe(Oid relid, LOCKMODE lockmode, bool orstronger)
Definition lmgr.c:351

References Assert, CacheInvalidateRelcacheByTuple(), CatalogTupleUpdate(), CheckRelationOidLockedByMe(), elog, ERROR, fb(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, ObjectIdGetDatum(), RowExclusiveLock, SearchSysCacheCopy1, ShareRowExclusiveLock, ShareUpdateExclusiveLock, HeapTupleData::t_self, table_close(), and table_open().

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

◆ SetRelationTableSpace()

void SetRelationTableSpace ( Relation  rel,
Oid  newTableSpaceId,
RelFileNumber  newRelFilenumber 
)
extern

Definition at line 3829 of file tablecmds.c.

3832{
3834 HeapTuple tuple;
3836 Form_pg_class rd_rel;
3837 Oid reloid = RelationGetRelid(rel);
3838
3840
3841 /* Get a modifiable copy of the relation's pg_class row. */
3843
3845 if (!HeapTupleIsValid(tuple))
3846 elog(ERROR, "cache lookup failed for relation %u", reloid);
3847 otid = tuple->t_self;
3848 rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3849
3850 /* Update the pg_class row. */
3851 rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3854 rd_rel->relfilenode = newRelFilenumber;
3857
3858 /*
3859 * Record dependency on tablespace. This is only required for relations
3860 * that have no physical storage.
3861 */
3862 if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3864 rd_rel->reltablespace);
3865
3866 heap_freetuple(tuple);
3868}
void changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId)
#define RelFileNumberIsValid(relnumber)
Definition relpath.h:27
bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
Definition tablecmds.c:3772

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

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