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

Go to the source code of this file.

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

Definition at line 24 of file tablecmds.h.

Function Documentation

◆ AlterRelationNamespaceInternal()

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

Definition at line 19082 of file tablecmds.c.

19086{
19087 HeapTuple classTup;
19088 Form_pg_class classForm;
19089 ObjectAddress thisobj;
19090 bool already_done = false;
19091
19092 /* no rel lock for relkind=c so use LOCKTAG_TUPLE */
19093 classTup = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(relOid));
19094 if (!HeapTupleIsValid(classTup))
19095 elog(ERROR, "cache lookup failed for relation %u", relOid);
19096 classForm = (Form_pg_class) GETSTRUCT(classTup);
19097
19098 Assert(classForm->relnamespace == oldNspOid);
19099
19100 thisobj.classId = RelationRelationId;
19101 thisobj.objectId = relOid;
19102 thisobj.objectSubId = 0;
19103
19104 /*
19105 * If the object has already been moved, don't move it again. If it's
19106 * already in the right place, don't move it, but still fire the object
19107 * access hook.
19108 */
19109 already_done = object_address_present(&thisobj, objsMoved);
19110 if (!already_done && oldNspOid != newNspOid)
19111 {
19112 ItemPointerData otid = classTup->t_self;
19113
19114 /* check for duplicate name (more friendly than unique-index failure) */
19115 if (get_relname_relid(NameStr(classForm->relname),
19116 newNspOid) != InvalidOid)
19117 ereport(ERROR,
19118 (errcode(ERRCODE_DUPLICATE_TABLE),
19119 errmsg("relation \"%s\" already exists in schema \"%s\"",
19120 NameStr(classForm->relname),
19121 get_namespace_name(newNspOid))));
19122
19123 /* classTup is a copy, so OK to scribble on */
19124 classForm->relnamespace = newNspOid;
19125
19126 CatalogTupleUpdate(classRel, &otid, classTup);
19127 UnlockTuple(classRel, &otid, InplaceUpdateTupleLock);
19128
19129
19130 /* Update dependency on schema if caller said so */
19131 if (hasDependEntry &&
19132 changeDependencyFor(RelationRelationId,
19133 relOid,
19134 NamespaceRelationId,
19135 oldNspOid,
19136 newNspOid) != 1)
19137 elog(ERROR, "could not change schema dependency for relation \"%s\"",
19138 NameStr(classForm->relname));
19139 }
19140 else
19141 UnlockTuple(classRel, &classTup->t_self, InplaceUpdateTupleLock);
19142 if (!already_done)
19143 {
19144 add_exact_object_address(&thisobj, objsMoved);
19145
19146 InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
19147 }
19148
19149 heap_freetuple(classTup);
19150}
#define NameStr(name)
Definition: c.h:765
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2769
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2709
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
Assert(PointerIsAligned(start, uint64))
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
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:3516
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:2035
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
FormData_pg_class * Form_pg_class
Definition: pg_class.h:156
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:457
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
#define InvalidOid
Definition: postgres_ext.h:37
ItemPointerData t_self
Definition: htup.h:65
HeapTuple SearchSysCacheLockedCopy1(int cacheId, Datum key1)
Definition: syscache.c:399

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

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

◆ AlterTable()

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

Definition at line 4532 of file tablecmds.c.

4534{
4535 Relation rel;
4536
4537 /* Caller is required to provide an adequate lock. */
4538 rel = relation_open(context->relid, NoLock);
4539
4541
4542 ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4543}
#define stmt
Definition: indent_codes.h:59
#define NoLock
Definition: lockdefs.h:34
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
static void CheckAlterTableIsSafe(Relation rel)
Definition: tablecmds.c:4447
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4873

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

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4606 of file tablecmds.c.

4607{
4608 /*
4609 * This only works if we read catalog tables using MVCC snapshots.
4610 */
4611 ListCell *lcmd;
4613
4614 foreach(lcmd, cmds)
4615 {
4616 AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4617 LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4618
4619 switch (cmd->subtype)
4620 {
4621 /*
4622 * These subcommands rewrite the heap, so require full locks.
4623 */
4624 case AT_AddColumn: /* may rewrite heap, in some cases and visible
4625 * to SELECT */
4626 case AT_SetAccessMethod: /* must rewrite heap */
4627 case AT_SetTableSpace: /* must rewrite heap */
4628 case AT_AlterColumnType: /* must rewrite heap */
4629 cmd_lockmode = AccessExclusiveLock;
4630 break;
4631
4632 /*
4633 * These subcommands may require addition of toast tables. If
4634 * we add a toast table to a table currently being scanned, we
4635 * might miss data added to the new toast table by concurrent
4636 * insert transactions.
4637 */
4638 case AT_SetStorage: /* may add toast tables, see
4639 * ATRewriteCatalogs() */
4640 cmd_lockmode = AccessExclusiveLock;
4641 break;
4642
4643 /*
4644 * Removing constraints can affect SELECTs that have been
4645 * optimized assuming the constraint holds true. See also
4646 * CloneFkReferenced.
4647 */
4648 case AT_DropConstraint: /* as DROP INDEX */
4649 case AT_DropNotNull: /* may change some SQL plans */
4650 cmd_lockmode = AccessExclusiveLock;
4651 break;
4652
4653 /*
4654 * Subcommands that may be visible to concurrent SELECTs
4655 */
4656 case AT_DropColumn: /* change visible to SELECT */
4657 case AT_AddColumnToView: /* CREATE VIEW */
4658 case AT_DropOids: /* used to equiv to DropColumn */
4659 case AT_EnableAlwaysRule: /* may change SELECT rules */
4660 case AT_EnableReplicaRule: /* may change SELECT rules */
4661 case AT_EnableRule: /* may change SELECT rules */
4662 case AT_DisableRule: /* may change SELECT rules */
4663 cmd_lockmode = AccessExclusiveLock;
4664 break;
4665
4666 /*
4667 * Changing owner may remove implicit SELECT privileges
4668 */
4669 case AT_ChangeOwner: /* change visible to SELECT */
4670 cmd_lockmode = AccessExclusiveLock;
4671 break;
4672
4673 /*
4674 * Changing foreign table options may affect optimization.
4675 */
4676 case AT_GenericOptions:
4678 cmd_lockmode = AccessExclusiveLock;
4679 break;
4680
4681 /*
4682 * These subcommands affect write operations only.
4683 */
4684 case AT_EnableTrig:
4687 case AT_EnableTrigAll:
4688 case AT_EnableTrigUser:
4689 case AT_DisableTrig:
4690 case AT_DisableTrigAll:
4691 case AT_DisableTrigUser:
4692 cmd_lockmode = ShareRowExclusiveLock;
4693 break;
4694
4695 /*
4696 * These subcommands affect write operations only. XXX
4697 * Theoretically, these could be ShareRowExclusiveLock.
4698 */
4699 case AT_ColumnDefault:
4701 case AT_AlterConstraint:
4702 case AT_AddIndex: /* from ADD CONSTRAINT */
4704 case AT_ReplicaIdentity:
4705 case AT_SetNotNull:
4710 case AT_AddIdentity:
4711 case AT_DropIdentity:
4712 case AT_SetIdentity:
4713 case AT_SetExpression:
4714 case AT_DropExpression:
4715 case AT_SetCompression:
4716 cmd_lockmode = AccessExclusiveLock;
4717 break;
4718
4719 case AT_AddConstraint:
4720 case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4721 case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4722 if (IsA(cmd->def, Constraint))
4723 {
4724 Constraint *con = (Constraint *) cmd->def;
4725
4726 switch (con->contype)
4727 {
4728 case CONSTR_EXCLUSION:
4729 case CONSTR_PRIMARY:
4730 case CONSTR_UNIQUE:
4731
4732 /*
4733 * Cases essentially the same as CREATE INDEX. We
4734 * could reduce the lock strength to ShareLock if
4735 * we can work out how to allow concurrent catalog
4736 * updates. XXX Might be set down to
4737 * ShareRowExclusiveLock but requires further
4738 * analysis.
4739 */
4740 cmd_lockmode = AccessExclusiveLock;
4741 break;
4742 case CONSTR_FOREIGN:
4743
4744 /*
4745 * We add triggers to both tables when we add a
4746 * Foreign Key, so the lock level must be at least
4747 * as strong as CREATE TRIGGER.
4748 */
4749 cmd_lockmode = ShareRowExclusiveLock;
4750 break;
4751
4752 default:
4753 cmd_lockmode = AccessExclusiveLock;
4754 }
4755 }
4756 break;
4757
4758 /*
4759 * These subcommands affect inheritance behaviour. Queries
4760 * started before us will continue to see the old inheritance
4761 * behaviour, while queries started after we commit will see
4762 * new behaviour. No need to prevent reads or writes to the
4763 * subtable while we hook it up though. Changing the TupDesc
4764 * may be a problem, so keep highest lock.
4765 */
4766 case AT_AddInherit:
4767 case AT_DropInherit:
4768 cmd_lockmode = AccessExclusiveLock;
4769 break;
4770
4771 /*
4772 * These subcommands affect implicit row type conversion. They
4773 * have affects similar to CREATE/DROP CAST on queries. don't
4774 * provide for invalidating parse trees as a result of such
4775 * changes, so we keep these at AccessExclusiveLock.
4776 */
4777 case AT_AddOf:
4778 case AT_DropOf:
4779 cmd_lockmode = AccessExclusiveLock;
4780 break;
4781
4782 /*
4783 * Only used by CREATE OR REPLACE VIEW which must conflict
4784 * with an SELECTs currently using the view.
4785 */
4787 cmd_lockmode = AccessExclusiveLock;
4788 break;
4789
4790 /*
4791 * These subcommands affect general strategies for performance
4792 * and maintenance, though don't change the semantic results
4793 * from normal data reads and writes. Delaying an ALTER TABLE
4794 * behind currently active writes only delays the point where
4795 * the new strategy begins to take effect, so there is no
4796 * benefit in waiting. In this case the minimum restriction
4797 * applies: we don't currently allow concurrent catalog
4798 * updates.
4799 */
4800 case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4801 case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4802 case AT_DropCluster: /* Uses MVCC in getIndexes() */
4803 case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4804 case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4805 cmd_lockmode = ShareUpdateExclusiveLock;
4806 break;
4807
4808 case AT_SetLogged:
4809 case AT_SetUnLogged:
4810 cmd_lockmode = AccessExclusiveLock;
4811 break;
4812
4813 case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4814 cmd_lockmode = ShareUpdateExclusiveLock;
4815 break;
4816
4817 /*
4818 * Rel options are more complex than first appears. Options
4819 * are set here for tables, views and indexes; for historical
4820 * reasons these can all be used with ALTER TABLE, so we can't
4821 * decide between them using the basic grammar.
4822 */
4823 case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4824 * getTables() */
4825 case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4826 * getTables() */
4827 cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4828 break;
4829
4830 case AT_AttachPartition:
4831 cmd_lockmode = ShareUpdateExclusiveLock;
4832 break;
4833
4834 case AT_DetachPartition:
4835 if (((PartitionCmd *) cmd->def)->concurrent)
4836 cmd_lockmode = ShareUpdateExclusiveLock;
4837 else
4838 cmd_lockmode = AccessExclusiveLock;
4839 break;
4840
4842 cmd_lockmode = ShareUpdateExclusiveLock;
4843 break;
4844
4845 case AT_MergePartitions:
4846 case AT_SplitPartition:
4847 cmd_lockmode = AccessExclusiveLock;
4848 break;
4849
4850 default: /* oops */
4851 elog(ERROR, "unrecognized alter table type: %d",
4852 (int) cmd->subtype);
4853 break;
4854 }
4855
4856 /*
4857 * Take the greatest lockmode from any subcommand
4858 */
4859 if (cmd_lockmode > lockmode)
4860 lockmode = cmd_lockmode;
4861 }
4862
4863 return lockmode;
4864}
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:164
@ CONSTR_FOREIGN
Definition: parsenodes.h:2838
@ CONSTR_UNIQUE
Definition: parsenodes.h:2836
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2837
@ CONSTR_PRIMARY
Definition: parsenodes.h:2835
@ AT_AddIndexConstraint
Definition: parsenodes.h:2465
@ AT_MergePartitions
Definition: parsenodes.h:2507
@ AT_DropOf
Definition: parsenodes.h:2496
@ AT_SetOptions
Definition: parsenodes.h:2453
@ AT_DropIdentity
Definition: parsenodes.h:2510
@ AT_DisableTrigUser
Definition: parsenodes.h:2488
@ AT_DropNotNull
Definition: parsenodes.h:2448
@ AT_AddOf
Definition: parsenodes.h:2495
@ AT_ResetOptions
Definition: parsenodes.h:2454
@ AT_ReplicaIdentity
Definition: parsenodes.h:2497
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2480
@ AT_EnableRowSecurity
Definition: parsenodes.h:2498
@ AT_AddColumnToView
Definition: parsenodes.h:2445
@ AT_ResetRelOptions
Definition: parsenodes.h:2479
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2483
@ AT_DropOids
Definition: parsenodes.h:2475
@ AT_SetIdentity
Definition: parsenodes.h:2509
@ AT_SetUnLogged
Definition: parsenodes.h:2474
@ AT_DisableTrig
Definition: parsenodes.h:2484
@ AT_SetCompression
Definition: parsenodes.h:2456
@ AT_DropExpression
Definition: parsenodes.h:2451
@ AT_AddIndex
Definition: parsenodes.h:2458
@ AT_EnableReplicaRule
Definition: parsenodes.h:2491
@ AT_DropConstraint
Definition: parsenodes.h:2466
@ AT_SetNotNull
Definition: parsenodes.h:2449
@ AT_ClusterOn
Definition: parsenodes.h:2471
@ AT_AddIdentity
Definition: parsenodes.h:2508
@ AT_ForceRowSecurity
Definition: parsenodes.h:2500
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2490
@ AT_SetAccessMethod
Definition: parsenodes.h:2476
@ AT_AlterColumnType
Definition: parsenodes.h:2468
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2505
@ AT_AddInherit
Definition: parsenodes.h:2493
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2462
@ AT_EnableTrig
Definition: parsenodes.h:2481
@ AT_DropColumn
Definition: parsenodes.h:2457
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2469
@ AT_DisableTrigAll
Definition: parsenodes.h:2486
@ AT_EnableRule
Definition: parsenodes.h:2489
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2501
@ AT_DetachPartition
Definition: parsenodes.h:2504
@ AT_SetStatistics
Definition: parsenodes.h:2452
@ AT_AttachPartition
Definition: parsenodes.h:2503
@ AT_AddConstraint
Definition: parsenodes.h:2460
@ AT_DropInherit
Definition: parsenodes.h:2494
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2482
@ AT_SetLogged
Definition: parsenodes.h:2473
@ AT_SetStorage
Definition: parsenodes.h:2455
@ AT_DisableRule
Definition: parsenodes.h:2492
@ AT_DisableRowSecurity
Definition: parsenodes.h:2499
@ AT_SetRelOptions
Definition: parsenodes.h:2478
@ AT_ChangeOwner
Definition: parsenodes.h:2470
@ AT_EnableTrigUser
Definition: parsenodes.h:2487
@ AT_SetExpression
Definition: parsenodes.h:2450
@ AT_ReAddConstraint
Definition: parsenodes.h:2461
@ AT_SetTableSpace
Definition: parsenodes.h:2477
@ AT_GenericOptions
Definition: parsenodes.h:2502
@ AT_ColumnDefault
Definition: parsenodes.h:2446
@ AT_CookedColumnDefault
Definition: parsenodes.h:2447
@ AT_AlterConstraint
Definition: parsenodes.h:2463
@ AT_EnableTrigAll
Definition: parsenodes.h:2485
@ AT_SplitPartition
Definition: parsenodes.h:2506
@ AT_DropCluster
Definition: parsenodes.h:2472
@ AT_ValidateConstraint
Definition: parsenodes.h:2464
@ AT_AddColumn
Definition: parsenodes.h:2444
#define lfirst(lc)
Definition: pg_list.h:172
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2155
AlterTableType subtype
Definition: parsenodes.h:2517
ConstrType contype
Definition: parsenodes.h:2862
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, IsA, lfirst, ShareRowExclusiveLock, ShareUpdateExclusiveLock, and AlterTableCmd::subtype.

Referenced by AlterTableInternal(), and ProcessUtilitySlow().

◆ AlterTableInternal()

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

Definition at line 4561 of file tablecmds.c.

4562{
4563 Relation rel;
4564 LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4565
4566 rel = relation_open(relid, lockmode);
4567
4569
4570 ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4571}
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4606

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4473 of file tablecmds.c.

4474{
4475 return RangeVarGetRelidExtended(stmt->relation, lockmode,
4476 stmt->missing_ok ? RVR_MISSING_OK : 0,
4478 stmt);
4479}
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:440
@ RVR_MISSING_OK
Definition: namespace.h:90
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:19614

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

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 17015 of file tablecmds.c.

17016{
17017 List *relations = NIL;
17018 ListCell *l;
17019 ScanKeyData key[1];
17020 Relation rel;
17021 TableScanDesc scan;
17022 HeapTuple tuple;
17023 Oid orig_tablespaceoid;
17024 Oid new_tablespaceoid;
17025 List *role_oids = roleSpecsToIds(stmt->roles);
17026
17027 /* Ensure we were not asked to move something we can't */
17028 if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
17029 stmt->objtype != OBJECT_MATVIEW)
17030 ereport(ERROR,
17031 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
17032 errmsg("only tables, indexes, and materialized views exist in tablespaces")));
17033
17034 /* Get the orig and new tablespace OIDs */
17035 orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
17036 new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
17037
17038 /* Can't move shared relations in to or out of pg_global */
17039 /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
17040 if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
17041 new_tablespaceoid == GLOBALTABLESPACE_OID)
17042 ereport(ERROR,
17043 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
17044 errmsg("cannot move relations in to or out of pg_global tablespace")));
17045
17046 /*
17047 * Must have CREATE rights on the new tablespace, unless it is the
17048 * database default tablespace (which all users implicitly have CREATE
17049 * rights on).
17050 */
17051 if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
17052 {
17053 AclResult aclresult;
17054
17055 aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
17056 ACL_CREATE);
17057 if (aclresult != ACLCHECK_OK)
17059 get_tablespace_name(new_tablespaceoid));
17060 }
17061
17062 /*
17063 * Now that the checks are done, check if we should set either to
17064 * InvalidOid because it is our database's default tablespace.
17065 */
17066 if (orig_tablespaceoid == MyDatabaseTableSpace)
17067 orig_tablespaceoid = InvalidOid;
17068
17069 if (new_tablespaceoid == MyDatabaseTableSpace)
17070 new_tablespaceoid = InvalidOid;
17071
17072 /* no-op */
17073 if (orig_tablespaceoid == new_tablespaceoid)
17074 return new_tablespaceoid;
17075
17076 /*
17077 * Walk the list of objects in the tablespace and move them. This will
17078 * only find objects in our database, of course.
17079 */
17080 ScanKeyInit(&key[0],
17081 Anum_pg_class_reltablespace,
17082 BTEqualStrategyNumber, F_OIDEQ,
17083 ObjectIdGetDatum(orig_tablespaceoid));
17084
17085 rel = table_open(RelationRelationId, AccessShareLock);
17086 scan = table_beginscan_catalog(rel, 1, key);
17087 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
17088 {
17089 Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
17090 Oid relOid = relForm->oid;
17091
17092 /*
17093 * Do not move objects in pg_catalog as part of this, if an admin
17094 * really wishes to do so, they can issue the individual ALTER
17095 * commands directly.
17096 *
17097 * Also, explicitly avoid any shared tables, temp tables, or TOAST
17098 * (TOAST will be moved with the main table).
17099 */
17100 if (IsCatalogNamespace(relForm->relnamespace) ||
17101 relForm->relisshared ||
17102 isAnyTempNamespace(relForm->relnamespace) ||
17103 IsToastNamespace(relForm->relnamespace))
17104 continue;
17105
17106 /* Only move the object type requested */
17107 if ((stmt->objtype == OBJECT_TABLE &&
17108 relForm->relkind != RELKIND_RELATION &&
17109 relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
17110 (stmt->objtype == OBJECT_INDEX &&
17111 relForm->relkind != RELKIND_INDEX &&
17112 relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
17113 (stmt->objtype == OBJECT_MATVIEW &&
17114 relForm->relkind != RELKIND_MATVIEW))
17115 continue;
17116
17117 /* Check if we are only moving objects owned by certain roles */
17118 if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
17119 continue;
17120
17121 /*
17122 * Handle permissions-checking here since we are locking the tables
17123 * and also to avoid doing a bunch of work only to fail part-way. Note
17124 * that permissions will also be checked by AlterTableInternal().
17125 *
17126 * Caller must be considered an owner on the table to move it.
17127 */
17128 if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
17130 NameStr(relForm->relname));
17131
17132 if (stmt->nowait &&
17134 ereport(ERROR,
17135 (errcode(ERRCODE_OBJECT_IN_USE),
17136 errmsg("aborting because lock on relation \"%s.%s\" is not available",
17137 get_namespace_name(relForm->relnamespace),
17138 NameStr(relForm->relname))));
17139 else
17141
17142 /* Add to our list of objects to move */
17143 relations = lappend_oid(relations, relOid);
17144 }
17145
17146 table_endscan(scan);
17148
17149 if (relations == NIL)
17151 (errcode(ERRCODE_NO_DATA_FOUND),
17152 errmsg("no matching relations in tablespace \"%s\" found",
17153 orig_tablespaceoid == InvalidOid ? "(database default)" :
17154 get_tablespace_name(orig_tablespaceoid))));
17155
17156 /* Everything is locked, loop through and move all of the relations. */
17157 foreach(l, relations)
17158 {
17159 List *cmds = NIL;
17161
17163 cmd->name = stmt->new_tablespacename;
17164
17165 cmds = lappend(cmds, cmd);
17166
17168 /* OID is set by AlterTableInternal */
17169 AlterTableInternal(lfirst_oid(l), cmds, false);
17171 }
17172
17173 return new_tablespaceoid;
17174}
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2654
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3836
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4090
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1426
#define OidIsValid(objectId)
Definition: c.h:788
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:261
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:243
#define NOTICE
Definition: elog.h:35
void EventTriggerAlterTableStart(Node *parsetree)
void EventTriggerAlterTableEnd(void)
Oid MyDatabaseTableSpace
Definition: globals.c:96
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1364
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:2153
Oid GetUserId(void)
Definition: miscinit.c:469
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3757
#define makeNode(_type_)
Definition: nodes.h:161
ObjectType get_relkind_objtype(char relkind)
@ OBJECT_MATVIEW
Definition: parsenodes.h:2375
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2394
@ OBJECT_INDEX
Definition: parsenodes.h:2372
@ OBJECT_TABLE
Definition: parsenodes.h:2393
#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
Definition: postgres_ext.h:32
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:135
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:985
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4561
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1652

References AccessExclusiveLock, AccessShareLock, ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTableInternal(), AT_SetTableSpace, BTEqualStrategyNumber, ConditionalLockRelationOid(), ereport, errcode(), errmsg(), ERROR, EventTriggerAlterTableEnd(), EventTriggerAlterTableStart(), ForwardScanDirection, get_namespace_name(), get_rel_relkind(), get_relkind_objtype(), get_tablespace_name(), get_tablespace_oid(), GETSTRUCT(), GetUserId(), heap_getnext(), InvalidOid, isAnyTempNamespace(), IsCatalogNamespace(), IsToastNamespace(), sort-test::key, lappend(), lappend_oid(), lfirst_oid, list_member_oid(), LockRelationOid(), makeNode, MyDatabaseTableSpace, AlterTableCmd::name, NameStr, 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 
)

Definition at line 18974 of file tablecmds.c.

18975{
18976 Relation rel;
18977 Oid relid;
18978 Oid oldNspOid;
18979 Oid nspOid;
18980 RangeVar *newrv;
18981 ObjectAddresses *objsMoved;
18982 ObjectAddress myself;
18983
18985 stmt->missing_ok ? RVR_MISSING_OK : 0,
18987 stmt);
18988
18989 if (!OidIsValid(relid))
18990 {
18992 (errmsg("relation \"%s\" does not exist, skipping",
18993 stmt->relation->relname)));
18994 return InvalidObjectAddress;
18995 }
18996
18997 rel = relation_open(relid, NoLock);
18998
18999 oldNspOid = RelationGetNamespace(rel);
19000
19001 /* If it's an owned sequence, disallow moving it by itself. */
19002 if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
19003 {
19004 Oid tableId;
19005 int32 colId;
19006
19007 if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
19008 sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
19009 ereport(ERROR,
19010 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
19011 errmsg("cannot move an owned sequence into another schema"),
19012 errdetail("Sequence \"%s\" is linked to table \"%s\".",
19014 get_rel_name(tableId))));
19015 }
19016
19017 /* Get and lock schema OID and check its permissions. */
19018 newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
19019 nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
19020
19021 /* common checks on switching namespaces */
19022 CheckSetNamespace(oldNspOid, nspOid);
19023
19024 objsMoved = new_object_addresses();
19025 AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
19026 free_object_addresses(objsMoved);
19027
19028 ObjectAddressSet(myself, RelationRelationId, relid);
19029
19030 if (oldschema)
19031 *oldschema = oldNspOid;
19032
19033 /* close rel, but keep lock until commit */
19034 relation_close(rel, NoLock);
19035
19036 return myself;
19037}
int32_t int32
Definition: c.h:548
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2664
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2949
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int errdetail(const char *fmt,...)
Definition: elog.c:1216
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2078
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:738
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3529
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:828
#define RelationGetRelationName(relation)
Definition: rel.h:549
#define RelationGetNamespace(relation)
Definition: rel.h:556
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Form_pg_class rd_rel
Definition: rel.h:111
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:19045

References AccessExclusiveLock, AlterTableNamespaceInternal(), CheckSetNamespace(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, ereport, errcode(), errdetail(), errmsg(), ERROR, 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 
)

Definition at line 19045 of file tablecmds.c.

19047{
19048 Relation classRel;
19049
19050 Assert(objsMoved != NULL);
19051
19052 /* OK, modify the pg_class row and pg_depend entry */
19053 classRel = table_open(RelationRelationId, RowExclusiveLock);
19054
19055 AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
19056 nspOid, true, objsMoved);
19057
19058 /* Fix the table's row type too, if it has one */
19059 if (OidIsValid(rel->rd_rel->reltype))
19060 AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid,
19061 false, /* isImplicitArray */
19062 false, /* ignoreDependent */
19063 false, /* errorOnTableType */
19064 objsMoved);
19065
19066 /* Fix other dependent stuff */
19067 AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
19068 AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
19069 objsMoved, AccessExclusiveLock);
19070 AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
19071 false, objsMoved);
19072
19073 table_close(classRel, RowExclusiveLock);
19074}
#define RowExclusiveLock
Definition: lockdefs.h:38
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
#define RelationGetRelid(relation)
Definition: rel.h:515
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:19082
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:19204
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:19159
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:4169

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

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 19487 of file tablecmds.c.

19489{
19490 ListCell *cur_item;
19491
19492 foreach(cur_item, on_commits)
19493 {
19494 OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
19495
19496 if (!isCommit && oc->creating_subid == mySubid)
19497 {
19498 /* cur_item must be removed */
19500 pfree(oc);
19501 }
19502 else
19503 {
19504 /* cur_item must be preserved */
19505 if (oc->creating_subid == mySubid)
19506 oc->creating_subid = parentSubid;
19507 if (oc->deleting_subid == mySubid)
19508 oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
19509 }
19510 }
19511}
#define InvalidSubTransactionId
Definition: c.h:677
void pfree(void *pointer)
Definition: mcxt.c:1616
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
SubTransactionId creating_subid
Definition: tablecmds.c:128
SubTransactionId deleting_subid
Definition: tablecmds.c:129
static List * on_commits
Definition: tablecmds.c:132

References OnCommitItem::creating_subid, OnCommitItem::deleting_subid, 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)

Definition at line 19455 of file tablecmds.c.

19456{
19457 ListCell *cur_item;
19458
19459 foreach(cur_item, on_commits)
19460 {
19461 OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
19462
19463 if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
19465 {
19466 /* cur_item must be removed */
19468 pfree(oc);
19469 }
19470 else
19471 {
19472 /* cur_item must be preserved */
19475 }
19476 }
19477}

References OnCommitItem::creating_subid, OnCommitItem::deleting_subid, 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 
)

Definition at line 16102 of file tablecmds.c.

16103{
16104 Relation target_rel;
16105 Relation class_rel;
16106 HeapTuple tuple;
16107 Form_pg_class tuple_class;
16108
16109 /*
16110 * Get exclusive lock till end of transaction on the target table. Use
16111 * relation_open so that we can work on indexes and sequences.
16112 */
16113 target_rel = relation_open(relationOid, lockmode);
16114
16115 /* Get its pg_class tuple, too */
16116 class_rel = table_open(RelationRelationId, RowExclusiveLock);
16117
16118 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
16119 if (!HeapTupleIsValid(tuple))
16120 elog(ERROR, "cache lookup failed for relation %u", relationOid);
16121 tuple_class = (Form_pg_class) GETSTRUCT(tuple);
16122
16123 /* Can we change the ownership of this tuple? */
16124 switch (tuple_class->relkind)
16125 {
16126 case RELKIND_RELATION:
16127 case RELKIND_VIEW:
16128 case RELKIND_MATVIEW:
16129 case RELKIND_FOREIGN_TABLE:
16130 case RELKIND_PARTITIONED_TABLE:
16131 /* ok to change owner */
16132 break;
16133 case RELKIND_INDEX:
16134 if (!recursing)
16135 {
16136 /*
16137 * Because ALTER INDEX OWNER used to be allowed, and in fact
16138 * is generated by old versions of pg_dump, we give a warning
16139 * and do nothing rather than erroring out. Also, to avoid
16140 * unnecessary chatter while restoring those old dumps, say
16141 * nothing at all if the command would be a no-op anyway.
16142 */
16143 if (tuple_class->relowner != newOwnerId)
16145 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16146 errmsg("cannot change owner of index \"%s\"",
16147 NameStr(tuple_class->relname)),
16148 errhint("Change the ownership of the index's table instead.")));
16149 /* quick hack to exit via the no-op path */
16150 newOwnerId = tuple_class->relowner;
16151 }
16152 break;
16153 case RELKIND_PARTITIONED_INDEX:
16154 if (recursing)
16155 break;
16156 ereport(ERROR,
16157 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16158 errmsg("cannot change owner of index \"%s\"",
16159 NameStr(tuple_class->relname)),
16160 errhint("Change the ownership of the index's table instead.")));
16161 break;
16162 case RELKIND_SEQUENCE:
16163 if (!recursing &&
16164 tuple_class->relowner != newOwnerId)
16165 {
16166 /* if it's an owned sequence, disallow changing it by itself */
16167 Oid tableId;
16168 int32 colId;
16169
16170 if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
16171 sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
16172 ereport(ERROR,
16173 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16174 errmsg("cannot change owner of sequence \"%s\"",
16175 NameStr(tuple_class->relname)),
16176 errdetail("Sequence \"%s\" is linked to table \"%s\".",
16177 NameStr(tuple_class->relname),
16178 get_rel_name(tableId))));
16179 }
16180 break;
16181 case RELKIND_COMPOSITE_TYPE:
16182 if (recursing)
16183 break;
16184 ereport(ERROR,
16185 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16186 errmsg("\"%s\" is a composite type",
16187 NameStr(tuple_class->relname)),
16188 /* translator: %s is an SQL ALTER command */
16189 errhint("Use %s instead.",
16190 "ALTER TYPE")));
16191 break;
16192 case RELKIND_TOASTVALUE:
16193 if (recursing)
16194 break;
16195 /* FALL THRU */
16196 default:
16197 ereport(ERROR,
16198 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16199 errmsg("cannot change owner of relation \"%s\"",
16200 NameStr(tuple_class->relname)),
16201 errdetail_relkind_not_supported(tuple_class->relkind)));
16202 }
16203
16204 /*
16205 * If the new owner is the same as the existing owner, consider the
16206 * command to have succeeded. This is for dump restoration purposes.
16207 */
16208 if (tuple_class->relowner != newOwnerId)
16209 {
16210 Datum repl_val[Natts_pg_class];
16211 bool repl_null[Natts_pg_class];
16212 bool repl_repl[Natts_pg_class];
16213 Acl *newAcl;
16214 Datum aclDatum;
16215 bool isNull;
16216 HeapTuple newtuple;
16217
16218 /* skip permission checks when recursing to index or toast table */
16219 if (!recursing)
16220 {
16221 /* Superusers can always do it */
16222 if (!superuser())
16223 {
16224 Oid namespaceOid = tuple_class->relnamespace;
16225 AclResult aclresult;
16226
16227 /* Otherwise, must be owner of the existing object */
16228 if (!object_ownercheck(RelationRelationId, relationOid, GetUserId()))
16230 RelationGetRelationName(target_rel));
16231
16232 /* Must be able to become new owner */
16233 check_can_set_role(GetUserId(), newOwnerId);
16234
16235 /* New owner must have CREATE privilege on namespace */
16236 aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId,
16237 ACL_CREATE);
16238 if (aclresult != ACLCHECK_OK)
16239 aclcheck_error(aclresult, OBJECT_SCHEMA,
16240 get_namespace_name(namespaceOid));
16241 }
16242 }
16243
16244 memset(repl_null, false, sizeof(repl_null));
16245 memset(repl_repl, false, sizeof(repl_repl));
16246
16247 repl_repl[Anum_pg_class_relowner - 1] = true;
16248 repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
16249
16250 /*
16251 * Determine the modified ACL for the new owner. This is only
16252 * necessary when the ACL is non-null.
16253 */
16254 aclDatum = SysCacheGetAttr(RELOID, tuple,
16255 Anum_pg_class_relacl,
16256 &isNull);
16257 if (!isNull)
16258 {
16259 newAcl = aclnewowner(DatumGetAclP(aclDatum),
16260 tuple_class->relowner, newOwnerId);
16261 repl_repl[Anum_pg_class_relacl - 1] = true;
16262 repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
16263 }
16264
16265 newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
16266
16267 CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
16268
16269 heap_freetuple(newtuple);
16270
16271 /*
16272 * We must similarly update any per-column ACLs to reflect the new
16273 * owner; for neatness reasons that's split out as a subroutine.
16274 */
16275 change_owner_fix_column_acls(relationOid,
16276 tuple_class->relowner,
16277 newOwnerId);
16278
16279 /*
16280 * Update owner dependency reference, if any. A composite type has
16281 * none, because it's tracked for the pg_type entry instead of here;
16282 * indexes and TOAST tables don't have their own entries either.
16283 */
16284 if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
16285 tuple_class->relkind != RELKIND_INDEX &&
16286 tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
16287 tuple_class->relkind != RELKIND_TOASTVALUE)
16288 changeDependencyOnOwner(RelationRelationId, relationOid,
16289 newOwnerId);
16290
16291 /*
16292 * Also change the ownership of the table's row type, if it has one
16293 */
16294 if (OidIsValid(tuple_class->reltype))
16295 AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
16296
16297 /*
16298 * If we are operating on a table or materialized view, also change
16299 * the ownership of any indexes and sequences that belong to the
16300 * relation, as well as its toast table (if it has one).
16301 */
16302 if (tuple_class->relkind == RELKIND_RELATION ||
16303 tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
16304 tuple_class->relkind == RELKIND_MATVIEW ||
16305 tuple_class->relkind == RELKIND_TOASTVALUE)
16306 {
16307 List *index_oid_list;
16308 ListCell *i;
16309
16310 /* Find all the indexes belonging to this relation */
16311 index_oid_list = RelationGetIndexList(target_rel);
16312
16313 /* For each index, recursively change its ownership */
16314 foreach(i, index_oid_list)
16315 ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
16316
16317 list_free(index_oid_list);
16318 }
16319
16320 /* If it has a toast table, recurse to change its ownership */
16321 if (tuple_class->reltoastrelid != InvalidOid)
16322 ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
16323 true, lockmode);
16324
16325 /* If it has dependent sequences, recurse to change them too */
16326 change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
16327 }
16328
16329 InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
16330
16331 ReleaseSysCache(tuple);
16332 table_close(class_rel, RowExclusiveLock);
16333 relation_close(target_rel, NoLock);
16334}
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1119
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5341
#define DatumGetAclP(X)
Definition: acl.h:120
int errhint(const char *fmt,...)
Definition: elog.c:1330
#define WARNING
Definition: elog.h:36
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
int i
Definition: isn.c:77
void list_free(List *list)
Definition: list.c:1546
@ OBJECT_SCHEMA
Definition: parsenodes.h:2388
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:316
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
uint64_t Datum
Definition: postgres.h:70
#define RelationGetDescr(relation)
Definition: rel.h:541
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4831
bool superuser(void)
Definition: superuser.c:46
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:220
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:595
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:16102
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:16408
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:16343
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:4000

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, 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, 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 AlterTypeOwner_oid(), ATExecChangeOwner(), ATExecCmd(), change_owner_recurse_to_sequences(), and shdepReassignOwned_Owner().

◆ BuildDescForRelation()

TupleDesc BuildDescForRelation ( const List columns)

Definition at line 1376 of file tablecmds.c.

1377{
1378 int natts;
1380 ListCell *l;
1381 TupleDesc desc;
1382 char *attname;
1383 Oid atttypid;
1384 int32 atttypmod;
1385 Oid attcollation;
1386 int attdim;
1387
1388 /*
1389 * allocate a new tuple descriptor
1390 */
1391 natts = list_length(columns);
1392 desc = CreateTemplateTupleDesc(natts);
1393
1394 attnum = 0;
1395
1396 foreach(l, columns)
1397 {
1398 ColumnDef *entry = lfirst(l);
1399 AclResult aclresult;
1401
1402 /*
1403 * for each entry in the list, get the name and type information from
1404 * the list and have TupleDescInitEntry fill in the attribute
1405 * information we need.
1406 */
1407 attnum++;
1408
1409 attname = entry->colname;
1410 typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
1411
1412 aclresult = object_aclcheck(TypeRelationId, atttypid, GetUserId(), ACL_USAGE);
1413 if (aclresult != ACLCHECK_OK)
1414 aclcheck_error_type(aclresult, atttypid);
1415
1416 attcollation = GetColumnDefCollation(NULL, entry, atttypid);
1417 attdim = list_length(entry->typeName->arrayBounds);
1418 if (attdim > PG_INT16_MAX)
1419 ereport(ERROR,
1420 errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1421 errmsg("too many array dimensions"));
1422
1423 if (entry->typeName->setof)
1424 ereport(ERROR,
1425 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
1426 errmsg("column \"%s\" cannot be declared SETOF",
1427 attname)));
1428
1430 atttypid, atttypmod, attdim);
1431 att = TupleDescAttr(desc, attnum - 1);
1432
1433 /* Override TupleDescInitEntry's settings as requested */
1434 TupleDescInitEntryCollation(desc, attnum, attcollation);
1435
1436 /* Fill in additional stuff not handled by TupleDescInitEntry */
1437 att->attnotnull = entry->is_not_null;
1438 att->attislocal = entry->is_local;
1439 att->attinhcount = entry->inhcount;
1440 att->attidentity = entry->identity;
1441 att->attgenerated = entry->generated;
1442 att->attcompression = GetAttributeCompression(att->atttypid, entry->compression);
1443 if (entry->storage)
1444 att->attstorage = entry->storage;
1445 else if (entry->storage_name)
1446 att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name);
1447
1449 }
1450
1451 return desc;
1452}
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:2973
int16 AttrNumber
Definition: attnum.h:21
#define PG_INT16_MAX
Definition: c.h:605
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
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
static int list_length(const List *l)
Definition: pg_list.h:152
bool is_not_null
Definition: parsenodes.h:759
char identity
Definition: parsenodes.h:765
char * storage_name
Definition: parsenodes.h:762
char * colname
Definition: parsenodes.h:754
TypeName * typeName
Definition: parsenodes.h:755
char generated
Definition: parsenodes.h:768
char storage
Definition: parsenodes.h:761
bool is_local
Definition: parsenodes.h:758
int16 inhcount
Definition: parsenodes.h:757
char * compression
Definition: parsenodes.h:756
bool setof
Definition: parsenodes.h:287
List * arrayBounds
Definition: parsenodes.h:291
static char GetAttributeCompression(Oid atttypid, const char *compression)
Definition: tablecmds.c:22037
static char GetAttributeStorage(Oid atttypid, const char *storagemode)
Definition: tablecmds.c:22075
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:182
void populate_compact_attribute(TupleDesc tupdesc, int attnum)
Definition: tupdesc.c:117
void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid)
Definition: tupdesc.c:1026
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:842
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, TypeName::arrayBounds, attname, attnum, ColumnDef::colname, ColumnDef::compression, CreateTemplateTupleDesc(), ereport, errcode(), errmsg(), ERROR, 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(), TupleDescInitEntry(), TupleDescInitEntryCollation(), ColumnDef::typeName, and typenameTypeIdAndMod().

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

◆ check_of_type()

void check_of_type ( HeapTuple  typetuple)

Definition at line 7172 of file tablecmds.c.

7173{
7174 Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
7175 bool typeOk = false;
7176
7177 if (typ->typtype == TYPTYPE_COMPOSITE)
7178 {
7179 Relation typeRelation;
7180
7181 Assert(OidIsValid(typ->typrelid));
7182 typeRelation = relation_open(typ->typrelid, AccessShareLock);
7183 typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
7184
7185 /*
7186 * Close the parent rel, but keep our AccessShareLock on it until xact
7187 * commit. That will prevent someone else from deleting or ALTERing
7188 * the type before the typed table creation/conversion commits.
7189 */
7190 relation_close(typeRelation, NoLock);
7191
7192 if (!typeOk)
7193 ereport(ERROR,
7194 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7195 errmsg("type %s is the row type of another table",
7196 format_type_be(typ->oid)),
7197 errdetail("A typed table must use a stand-alone composite type created with CREATE TYPE.")));
7198 }
7199 else
7200 ereport(ERROR,
7201 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7202 errmsg("type %s is not a composite type",
7203 format_type_be(typ->oid))));
7204}
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261

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

Referenced by ATExecAddOf(), and transformOfType().

◆ CheckRelationTableSpaceMove()

bool CheckRelationTableSpaceMove ( Relation  rel,
Oid  newTableSpaceId 
)

Definition at line 3691 of file tablecmds.c.

3692{
3693 Oid oldTableSpaceId;
3694
3695 /*
3696 * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3697 * stored as 0.
3698 */
3699 oldTableSpaceId = rel->rd_rel->reltablespace;
3700 if (newTableSpaceId == oldTableSpaceId ||
3701 (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3702 return false;
3703
3704 /*
3705 * We cannot support moving mapped relations into different tablespaces.
3706 * (In particular this eliminates all shared catalogs.)
3707 */
3708 if (RelationIsMapped(rel))
3709 ereport(ERROR,
3710 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3711 errmsg("cannot move system relation \"%s\"",
3713
3714 /* Cannot move a non-shared relation into pg_global */
3715 if (newTableSpaceId == GLOBALTABLESPACE_OID)
3716 ereport(ERROR,
3717 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3718 errmsg("only shared relations can be placed in pg_global tablespace")));
3719
3720 /*
3721 * Do not allow moving temp tables of other backends ... their local
3722 * buffer manager is not going to cope.
3723 */
3724 if (RELATION_IS_OTHER_TEMP(rel))
3725 ereport(ERROR,
3726 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3727 errmsg("cannot move temporary tables of other sessions")));
3728
3729 return true;
3730}
#define RelationIsMapped(relation)
Definition: rel.h:564
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:668

References ereport, errcode(), errmsg(), ERROR, 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 
)

Definition at line 4414 of file tablecmds.c.

4415{
4416 int expected_refcnt;
4417
4418 expected_refcnt = rel->rd_isnailed ? 2 : 1;
4419 if (rel->rd_refcnt != expected_refcnt)
4420 ereport(ERROR,
4421 (errcode(ERRCODE_OBJECT_IN_USE),
4422 /* translator: first %s is a SQL command, eg ALTER TABLE */
4423 errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
4425
4426 if (rel->rd_rel->relkind != RELKIND_INDEX &&
4427 rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
4429 ereport(ERROR,
4430 (errcode(ERRCODE_OBJECT_IN_USE),
4431 /* translator: first %s is a SQL command, eg ALTER TABLE */
4432 errmsg("cannot %s \"%s\" because it has pending trigger events",
4434}
int rd_refcnt
Definition: rel.h:59
bool rd_isnailed
Definition: rel.h:62
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:6060

References AfterTriggerPendingOnRel(), ereport, errcode(), errmsg(), ERROR, 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 
)

Definition at line 769 of file tablecmds.c.

771{
772 char relname[NAMEDATALEN];
773 Oid namespaceId;
774 Oid relationId;
775 Oid tablespaceId;
776 Relation rel;
778 List *inheritOids;
779 List *old_constraints;
780 List *old_notnulls;
781 List *rawDefaults;
782 List *cookedDefaults;
783 List *nncols;
784 Datum reloptions;
785 ListCell *listptr;
787 bool partitioned;
788 const char *const validnsps[] = HEAP_RELOPT_NAMESPACES;
789 Oid ofTypeId;
790 ObjectAddress address;
791 LOCKMODE parentLockmode;
792 Oid accessMethodId = InvalidOid;
793
794 /*
795 * Truncate relname to appropriate length (probably a waste of time, as
796 * parser should have done this already).
797 */
798 strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
799
800 /*
801 * Check consistency of arguments
802 */
803 if (stmt->oncommit != ONCOMMIT_NOOP
804 && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
806 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
807 errmsg("ON COMMIT can only be used on temporary tables")));
808
809 if (stmt->partspec != NULL)
810 {
811 if (relkind != RELKIND_RELATION)
812 elog(ERROR, "unexpected relkind: %d", (int) relkind);
813
814 relkind = RELKIND_PARTITIONED_TABLE;
815 partitioned = true;
816 }
817 else
818 partitioned = false;
819
820 if (relkind == RELKIND_PARTITIONED_TABLE &&
821 stmt->relation->relpersistence == RELPERSISTENCE_UNLOGGED)
823 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
824 errmsg("partitioned tables cannot be unlogged")));
825
826 /*
827 * Look up the namespace in which we are supposed to create the relation,
828 * check we have permission to create there, lock it against concurrent
829 * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
830 * namespace is selected.
831 */
832 namespaceId =
834
835 /*
836 * Security check: disallow creating temp tables from security-restricted
837 * code. This is needed because calling code might not expect untrusted
838 * tables to appear in pg_temp at the front of its search path.
839 */
840 if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
843 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
844 errmsg("cannot create temporary table within security-restricted operation")));
845
846 /*
847 * Determine the lockmode to use when scanning parents. A self-exclusive
848 * lock is needed here.
849 *
850 * For regular inheritance, if two backends attempt to add children to the
851 * same parent simultaneously, and that parent has no pre-existing
852 * children, then both will attempt to update the parent's relhassubclass
853 * field, leading to a "tuple concurrently updated" error. Also, this
854 * interlocks against a concurrent ANALYZE on the parent table, which
855 * might otherwise be attempting to clear the parent's relhassubclass
856 * field, if its previous children were recently dropped.
857 *
858 * If the child table is a partition, then we instead grab an exclusive
859 * lock on the parent because its partition descriptor will be changed by
860 * addition of the new partition.
861 */
862 parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
864
865 /* Determine the list of OIDs of the parents. */
866 inheritOids = NIL;
867 foreach(listptr, stmt->inhRelations)
868 {
869 RangeVar *rv = (RangeVar *) lfirst(listptr);
870 Oid parentOid;
871
872 parentOid = RangeVarGetRelid(rv, parentLockmode, false);
873
874 /*
875 * Reject duplications in the list of parents.
876 */
877 if (list_member_oid(inheritOids, parentOid))
879 (errcode(ERRCODE_DUPLICATE_TABLE),
880 errmsg("relation \"%s\" would be inherited from more than once",
881 get_rel_name(parentOid))));
882
883 inheritOids = lappend_oid(inheritOids, parentOid);
884 }
885
886 /*
887 * Select tablespace to use: an explicitly indicated one, or (in the case
888 * of a partitioned table) the parent's, if it has one.
889 */
890 if (stmt->tablespacename)
891 {
892 tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
893
894 if (partitioned && tablespaceId == MyDatabaseTableSpace)
896 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
897 errmsg("cannot specify default tablespace for partitioned relations")));
898 }
899 else if (stmt->partbound)
900 {
901 Assert(list_length(inheritOids) == 1);
902 tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
903 }
904 else
905 tablespaceId = InvalidOid;
906
907 /* still nothing? use the default */
908 if (!OidIsValid(tablespaceId))
909 tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
910 partitioned);
911
912 /* Check permissions except when using database's default */
913 if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
914 {
915 AclResult aclresult;
916
917 aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, GetUserId(),
918 ACL_CREATE);
919 if (aclresult != ACLCHECK_OK)
921 get_tablespace_name(tablespaceId));
922 }
923
924 /* In all cases disallow placing user relations in pg_global */
925 if (tablespaceId == GLOBALTABLESPACE_OID)
927 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
928 errmsg("only shared relations can be placed in pg_global tablespace")));
929
930 /* Identify user ID that will own the table */
931 if (!OidIsValid(ownerId))
932 ownerId = GetUserId();
933
934 /*
935 * Parse and validate reloptions, if any.
936 */
937 reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
938 true, false);
939
940 switch (relkind)
941 {
942 case RELKIND_VIEW:
943 (void) view_reloptions(reloptions, true);
944 break;
945 case RELKIND_PARTITIONED_TABLE:
946 (void) partitioned_table_reloptions(reloptions, true);
947 break;
948 default:
949 (void) heap_reloptions(relkind, reloptions, true);
950 }
951
952 if (stmt->ofTypename)
953 {
954 AclResult aclresult;
955
956 ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
957
958 aclresult = object_aclcheck(TypeRelationId, ofTypeId, GetUserId(), ACL_USAGE);
959 if (aclresult != ACLCHECK_OK)
960 aclcheck_error_type(aclresult, ofTypeId);
961 }
962 else
963 ofTypeId = InvalidOid;
964
965 /*
966 * Look up inheritance ancestors and generate relation schema, including
967 * inherited attributes. (Note that stmt->tableElts is destructively
968 * modified by MergeAttributes.)
969 */
970 stmt->tableElts =
971 MergeAttributes(stmt->tableElts, inheritOids,
972 stmt->relation->relpersistence,
973 stmt->partbound != NULL,
974 &old_constraints, &old_notnulls);
975
976 /*
977 * Create a tuple descriptor from the relation schema. Note that this
978 * deals with column names, types, and in-descriptor NOT NULL flags, but
979 * not default values, NOT NULL or CHECK constraints; we handle those
980 * below.
981 */
983
984 /*
985 * Find columns with default values and prepare for insertion of the
986 * defaults. Pre-cooked (that is, inherited) defaults go into a list of
987 * CookedConstraint structs that we'll pass to heap_create_with_catalog,
988 * while raw defaults go into a list of RawColumnDefault structs that will
989 * be processed by AddRelationNewConstraints. (We can't deal with raw
990 * expressions until we can do transformExpr.)
991 */
992 rawDefaults = NIL;
993 cookedDefaults = NIL;
994 attnum = 0;
995
996 foreach(listptr, stmt->tableElts)
997 {
998 ColumnDef *colDef = lfirst(listptr);
999
1000 attnum++;
1001 if (colDef->raw_default != NULL)
1002 {
1003 RawColumnDefault *rawEnt;
1004
1005 Assert(colDef->cooked_default == NULL);
1006
1008 rawEnt->attnum = attnum;
1009 rawEnt->raw_default = colDef->raw_default;
1010 rawEnt->generated = colDef->generated;
1011 rawDefaults = lappend(rawDefaults, rawEnt);
1012 }
1013 else if (colDef->cooked_default != NULL)
1014 {
1015 CookedConstraint *cooked;
1016
1018 cooked->contype = CONSTR_DEFAULT;
1019 cooked->conoid = InvalidOid; /* until created */
1020 cooked->name = NULL;
1021 cooked->attnum = attnum;
1022 cooked->expr = colDef->cooked_default;
1023 cooked->is_enforced = true;
1024 cooked->skip_validation = false;
1025 cooked->is_local = true; /* not used for defaults */
1026 cooked->inhcount = 0; /* ditto */
1027 cooked->is_no_inherit = false;
1028 cookedDefaults = lappend(cookedDefaults, cooked);
1029 }
1030 }
1031
1032 /*
1033 * For relations with table AM and partitioned tables, select access
1034 * method to use: an explicitly indicated one, or (in the case of a
1035 * partitioned table) the parent's, if it has one.
1036 */
1037 if (stmt->accessMethod != NULL)
1038 {
1039 Assert(RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE);
1040 accessMethodId = get_table_am_oid(stmt->accessMethod, false);
1041 }
1042 else if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE)
1043 {
1044 if (stmt->partbound)
1045 {
1046 Assert(list_length(inheritOids) == 1);
1047 accessMethodId = get_rel_relam(linitial_oid(inheritOids));
1048 }
1049
1050 if (RELKIND_HAS_TABLE_AM(relkind) && !OidIsValid(accessMethodId))
1051 accessMethodId = get_table_am_oid(default_table_access_method, false);
1052 }
1053
1054 /*
1055 * Create the relation. Inherited defaults and CHECK constraints are
1056 * passed in for immediate handling --- since they don't need parsing,
1057 * they can be stored immediately.
1058 */
1059 relationId = heap_create_with_catalog(relname,
1060 namespaceId,
1061 tablespaceId,
1062 InvalidOid,
1063 InvalidOid,
1064 ofTypeId,
1065 ownerId,
1066 accessMethodId,
1067 descriptor,
1068 list_concat(cookedDefaults,
1069 old_constraints),
1070 relkind,
1071 stmt->relation->relpersistence,
1072 false,
1073 false,
1074 stmt->oncommit,
1075 reloptions,
1076 true,
1078 false,
1079 InvalidOid,
1080 typaddress);
1081
1082 /*
1083 * We must bump the command counter to make the newly-created relation
1084 * tuple visible for opening.
1085 */
1087
1088 /*
1089 * Open the new relation and acquire exclusive lock on it. This isn't
1090 * really necessary for locking out other backends (since they can't see
1091 * the new rel anyway until we commit), but it keeps the lock manager from
1092 * complaining about deadlock risks.
1093 */
1094 rel = relation_open(relationId, AccessExclusiveLock);
1095
1096 /*
1097 * Now add any newly specified column default and generation expressions
1098 * to the new relation. These are passed to us in the form of raw
1099 * parsetrees; we need to transform them to executable expression trees
1100 * before they can be added. The most convenient way to do that is to
1101 * apply the parser's transformExpr routine, but transformExpr doesn't
1102 * work unless we have a pre-existing relation. So, the transformation has
1103 * to be postponed to this final step of CREATE TABLE.
1104 *
1105 * This needs to be before processing the partitioning clauses because
1106 * those could refer to generated columns.
1107 */
1108 if (rawDefaults)
1109 AddRelationNewConstraints(rel, rawDefaults, NIL,
1110 true, true, false, queryString);
1111
1112 /*
1113 * Make column generation expressions visible for use by partitioning.
1114 */
1116
1117 /* Process and store partition bound, if any. */
1118 if (stmt->partbound)
1119 {
1120 PartitionBoundSpec *bound;
1121 ParseState *pstate;
1122 Oid parentId = linitial_oid(inheritOids),
1123 defaultPartOid;
1124 Relation parent,
1125 defaultRel = NULL;
1126 ParseNamespaceItem *nsitem;
1127
1128 /* Already have strong enough lock on the parent */
1129 parent = table_open(parentId, NoLock);
1130
1131 /*
1132 * We are going to try to validate the partition bound specification
1133 * against the partition key of parentRel, so it better have one.
1134 */
1135 if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1136 ereport(ERROR,
1137 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1138 errmsg("\"%s\" is not partitioned",
1139 RelationGetRelationName(parent))));
1140
1141 /*
1142 * The partition constraint of the default partition depends on the
1143 * partition bounds of every other partition. It is possible that
1144 * another backend might be about to execute a query on the default
1145 * partition table, and that the query relies on previously cached
1146 * default partition constraints. We must therefore take a table lock
1147 * strong enough to prevent all queries on the default partition from
1148 * proceeding until we commit and send out a shared-cache-inval notice
1149 * that will make them update their index lists.
1150 *
1151 * Order of locking: The relation being added won't be visible to
1152 * other backends until it is committed, hence here in
1153 * DefineRelation() the order of locking the default partition and the
1154 * relation being added does not matter. But at all other places we
1155 * need to lock the default relation before we lock the relation being
1156 * added or removed i.e. we should take the lock in same order at all
1157 * the places such that lock parent, lock default partition and then
1158 * lock the partition so as to avoid a deadlock.
1159 */
1160 defaultPartOid =
1162 true));
1163 if (OidIsValid(defaultPartOid))
1164 defaultRel = table_open(defaultPartOid, AccessExclusiveLock);
1165
1166 /* Transform the bound values */
1167 pstate = make_parsestate(NULL);
1168 pstate->p_sourcetext = queryString;
1169
1170 /*
1171 * Add an nsitem containing this relation, so that transformExpr
1172 * called on partition bound expressions is able to report errors
1173 * using a proper context.
1174 */
1175 nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
1176 NULL, false, false);
1177 addNSItemToQuery(pstate, nsitem, false, true, true);
1178
1179 bound = transformPartitionBound(pstate, parent, stmt->partbound);
1180
1181 /*
1182 * Check first that the new partition's bound is valid and does not
1183 * overlap with any of existing partitions of the parent.
1184 */
1185 check_new_partition_bound(relname, parent, bound, pstate);
1186
1187 /*
1188 * If the default partition exists, its partition constraints will
1189 * change after the addition of this new partition such that it won't
1190 * allow any row that qualifies for this new partition. So, check that
1191 * the existing data in the default partition satisfies the constraint
1192 * as it will exist after adding this partition.
1193 */
1194 if (OidIsValid(defaultPartOid))
1195 {
1196 check_default_partition_contents(parent, defaultRel, bound);
1197 /* Keep the lock until commit. */
1198 table_close(defaultRel, NoLock);
1199 }
1200
1201 /* Update the pg_class entry. */
1202 StorePartitionBound(rel, parent, bound);
1203
1204 table_close(parent, NoLock);
1205 }
1206
1207 /* Store inheritance information for new rel. */
1208 StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
1209
1210 /*
1211 * Process the partitioning specification (if any) and store the partition
1212 * key information into the catalog.
1213 */
1214 if (partitioned)
1215 {
1216 ParseState *pstate;
1217 int partnatts;
1218 AttrNumber partattrs[PARTITION_MAX_KEYS];
1219 Oid partopclass[PARTITION_MAX_KEYS];
1220 Oid partcollation[PARTITION_MAX_KEYS];
1221 List *partexprs = NIL;
1222
1223 pstate = make_parsestate(NULL);
1224 pstate->p_sourcetext = queryString;
1225
1226 partnatts = list_length(stmt->partspec->partParams);
1227
1228 /* Protect fixed-size arrays here and in executor */
1229 if (partnatts > PARTITION_MAX_KEYS)
1230 ereport(ERROR,
1231 (errcode(ERRCODE_TOO_MANY_COLUMNS),
1232 errmsg("cannot partition using more than %d columns",
1234
1235 /*
1236 * We need to transform the raw parsetrees corresponding to partition
1237 * expressions into executable expression trees. Like column defaults
1238 * and CHECK constraints, we could not have done the transformation
1239 * earlier.
1240 */
1241 stmt->partspec = transformPartitionSpec(rel, stmt->partspec);
1242
1243 ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
1244 partattrs, &partexprs, partopclass,
1245 partcollation, stmt->partspec->strategy);
1246
1247 StorePartitionKey(rel, stmt->partspec->strategy, partnatts, partattrs,
1248 partexprs,
1249 partopclass, partcollation);
1250
1251 /* make it all visible */
1253 }
1254
1255 /*
1256 * If we're creating a partition, create now all the indexes, triggers,
1257 * FKs defined in the parent.
1258 *
1259 * We can't do it earlier, because DefineIndex wants to know the partition
1260 * key which we just stored.
1261 */
1262 if (stmt->partbound)
1263 {
1264 Oid parentId = linitial_oid(inheritOids);
1265 Relation parent;
1266 List *idxlist;
1267 ListCell *cell;
1268
1269 /* Already have strong enough lock on the parent */
1270 parent = table_open(parentId, NoLock);
1271 idxlist = RelationGetIndexList(parent);
1272
1273 /*
1274 * For each index in the parent table, create one in the partition
1275 */
1276 foreach(cell, idxlist)
1277 {
1279 AttrMap *attmap;
1280 IndexStmt *idxstmt;
1281 Oid constraintOid;
1282
1283 if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1284 {
1285 if (idxRel->rd_index->indisunique)
1286 ereport(ERROR,
1287 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1288 errmsg("cannot create foreign partition of partitioned table \"%s\"",
1289 RelationGetRelationName(parent)),
1290 errdetail("Table \"%s\" contains indexes that are unique.",
1291 RelationGetRelationName(parent))));
1292 else
1293 {
1295 continue;
1296 }
1297 }
1298
1300 RelationGetDescr(parent),
1301 false);
1302 idxstmt =
1303 generateClonedIndexStmt(NULL, idxRel,
1304 attmap, &constraintOid);
1305 DefineIndex(NULL,
1306 RelationGetRelid(rel),
1307 idxstmt,
1308 InvalidOid,
1309 RelationGetRelid(idxRel),
1310 constraintOid,
1311 -1,
1312 false, false, false, false, false);
1313
1315 }
1316
1317 list_free(idxlist);
1318
1319 /*
1320 * If there are any row-level triggers, clone them to the new
1321 * partition.
1322 */
1323 if (parent->trigdesc != NULL)
1324 CloneRowTriggersToPartition(parent, rel);
1325
1326 /*
1327 * And foreign keys too. Note that because we're freshly creating the
1328 * table, there is no need to verify these new constraints.
1329 */
1330 CloneForeignKeyConstraints(NULL, parent, rel);
1331
1332 table_close(parent, NoLock);
1333 }
1334
1335 /*
1336 * Now add any newly specified CHECK constraints to the new relation. Same
1337 * as for defaults above, but these need to come after partitioning is set
1338 * up.
1339 */
1340 if (stmt->constraints)
1341 AddRelationNewConstraints(rel, NIL, stmt->constraints,
1342 true, true, false, queryString);
1343
1344 /*
1345 * Finally, merge the not-null constraints that are declared directly with
1346 * those that come from parent relations (making sure to count inheritance
1347 * appropriately for each), create them, and set the attnotnull flag on
1348 * columns that don't yet have it.
1349 */
1350 nncols = AddRelationNotNullConstraints(rel, stmt->nnconstraints,
1351 old_notnulls);
1352 foreach_int(attrnum, nncols)
1353 set_attnotnull(NULL, rel, attrnum, true, false);
1354
1355 ObjectAddressSet(address, RelationRelationId, relationId);
1356
1357 /*
1358 * Clean up. We keep lock on new relation (although it shouldn't be
1359 * visible to anyone else anyway, until commit).
1360 */
1361 relation_close(rel, NoLock);
1362
1363 return address;
1364}
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)
Definition: tablespace.c:1143
#define palloc_object(type)
Definition: fe_memutils.h:74
bool allowSystemTableMods
Definition: globals.c:130
void StorePartitionKey(Relation rel, char strategy, int16 partnatts, AttrNumber *partattrs, List *partexprs, Oid *partopclass, Oid *partcollation)
Definition: heap.c:3894
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:1122
void StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound)
Definition: heap.c:4050
List * AddRelationNotNullConstraints(Relation rel, List *constraints, List *old_notnulls)
Definition: heap.c:2894
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2385
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
ObjectAddress DefineIndex(ParseState *pstate, Oid tableId, 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:544
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
Oid get_rel_relam(Oid relid)
Definition: lsyscache.c:2250
Oid get_rel_tablespace(Oid relid)
Definition: lsyscache.c:2204
bool InSecurityRestrictedOperation(void)
Definition: miscinit.c:639
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:98
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:39
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
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
Definition: parsenodes.h:2831
void check_new_partition_bound(char *relname, Relation parent, PartitionBoundSpec *spec, ParseState *pstate)
Definition: partbounds.c:2889
void check_default_partition_contents(Relation parent, Relation default_rel, PartitionBoundSpec *new_spec)
Definition: partbounds.c:3244
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:38
#define PARTITION_MAX_KEYS
#define NAMEDATALEN
#define linitial_oid(l)
Definition: pg_list.h:180
#define foreach_int(var, lst)
Definition: pg_list.h:470
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
@ ONCOMMIT_NOOP
Definition: primnodes.h:58
bytea * view_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:2045
bytea * partitioned_table_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:2031
Datum transformRelOptions(Datum oldOptions, List *defList, const char *nameSpace, const char *const validnsps[], bool acceptOidsOff, bool isReset)
Definition: reloptions.c:1176
bytea * heap_reloptions(char relkind, Datum reloptions, bool validate)
Definition: reloptions.c:2066
#define HEAP_RELOPT_NAMESPACES
Definition: reloptions.h:61
Definition: attmap.h:35
Node * cooked_default
Definition: parsenodes.h:764
Node * raw_default
Definition: parsenodes.h:763
Oid conoid
Definition: heap.h:39
char * name
Definition: heap.h:40
AttrNumber attnum
Definition: heap.h:41
bool skip_validation
Definition: heap.h:44
bool is_enforced
Definition: heap.h:43
bool is_no_inherit
Definition: heap.h:47
int16 inhcount
Definition: heap.h:46
bool is_local
Definition: heap.h:45
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:42
const char * p_sourcetext
Definition: parse_node.h:195
Node * raw_default
Definition: heap.h:31
AttrNumber attnum
Definition: heap.h:30
char generated
Definition: heap.h:32
TriggerDesc * trigdesc
Definition: rel.h:117
Form_pg_index rd_index
Definition: rel.h:192
char * default_table_access_method
Definition: tableam.c:49
TupleDesc BuildDescForRelation(const List *columns)
Definition: tablecmds.c:1376
static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, PartitionStrategy strategy)
Definition: tablecmds.c:19813
static void CloneRowTriggersToPartition(Relation parent, Relation partition)
Definition: tablecmds.c:20800
static void StoreCatalogInheritance(Oid relationId, List *supers, bool child_is_partition)
Definition: tablecmds.c:3519
static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel, Relation partitionRel)
Definition: tablecmds.c:11247
static PartitionSpec * transformPartitionSpec(Relation rel, PartitionSpec *partspec)
Definition: tablecmds.c:19755
static void set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool is_valid, bool queue_validation)
Definition: tablecmds.c:7869
static List * MergeAttributes(List *columns, const List *supers, char relpersistence, bool is_partition, List **supconstr, List **supnotnulls)
Definition: tablecmds.c:2545
void CommandCounterIncrement(void)
Definition: xact.c:1101

References AccessExclusiveLock, AccessShareLock, ACL_CREATE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, addNSItemToQuery(), addRangeTableEntryForRelation(), AddRelationNewConstraints(), AddRelationNotNullConstraints(), allowSystemTableMods, Assert(), RawColumnDefault::attnum, CookedConstraint::attnum, attnum, build_attrmap_by_name(), BuildDescForRelation(), check_default_partition_contents(), check_new_partition_bound(), CloneForeignKeyConstraints(), CloneRowTriggersToPartition(), CommandCounterIncrement(), ComputePartitionAttrs(), CookedConstraint::conoid, CONSTR_DEFAULT, CookedConstraint::contype, ColumnDef::cooked_default, default_table_access_method, DefineIndex(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, CookedConstraint::expr, foreach_int, generateClonedIndexStmt(), RawColumnDefault::generated, ColumnDef::generated, 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(), CookedConstraint::inhcount, InSecurityRestrictedOperation(), InvalidOid, CookedConstraint::is_enforced, CookedConstraint::is_local, CookedConstraint::is_no_inherit, lappend(), lappend_oid(), lfirst, lfirst_oid, linitial_oid, list_concat(), list_free(), list_length(), list_member_oid(), make_parsestate(), MergeAttributes(), MyDatabaseTableSpace, CookedConstraint::name, NAMEDATALEN, NIL, NoLock, object_aclcheck(), OBJECT_TABLESPACE, ObjectAddressSet, OidIsValid, ONCOMMIT_NOOP, ParseState::p_sourcetext, palloc_object, PARTITION_MAX_KEYS, partitioned_table_reloptions(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelid, RawColumnDefault::raw_default, ColumnDef::raw_default, RelationData::rd_index, RelationData::rd_rel, relation_close(), relation_open(), RelationGetDescr, RelationGetIndexList(), RelationGetPartitionDesc(), RelationGetRelationName, RelationGetRelid, relname, set_attnotnull(), ShareUpdateExclusiveLock, CookedConstraint::skip_validation, stmt, StoreCatalogInheritance(), StorePartitionBound(), StorePartitionKey(), strlcpy(), table_close(), table_open(), transformPartitionBound(), transformPartitionSpec(), transformRelOptions(), RelationData::trigdesc, typenameTypeId(), and view_reloptions().

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

◆ ExecuteTruncate()

void ExecuteTruncate ( TruncateStmt stmt)

Definition at line 1857 of file tablecmds.c.

1858{
1859 List *rels = NIL;
1860 List *relids = NIL;
1861 List *relids_logged = NIL;
1862 ListCell *cell;
1863
1864 /*
1865 * Open, exclusive-lock, and check all the explicitly-specified relations
1866 */
1867 foreach(cell, stmt->relations)
1868 {
1869 RangeVar *rv = lfirst(cell);
1870 Relation rel;
1871 bool recurse = rv->inh;
1872 Oid myrelid;
1873 LOCKMODE lockmode = AccessExclusiveLock;
1874
1875 myrelid = RangeVarGetRelidExtended(rv, lockmode,
1877 NULL);
1878
1879 /* don't throw error for "TRUNCATE foo, foo" */
1880 if (list_member_oid(relids, myrelid))
1881 continue;
1882
1883 /* open the relation, we already hold a lock on it */
1884 rel = table_open(myrelid, NoLock);
1885
1886 /*
1887 * RangeVarGetRelidExtended() has done most checks with its callback,
1888 * but other checks with the now-opened Relation remain.
1889 */
1891
1892 rels = lappend(rels, rel);
1893 relids = lappend_oid(relids, myrelid);
1894
1895 /* Log this relation only if needed for logical decoding */
1897 relids_logged = lappend_oid(relids_logged, myrelid);
1898
1899 if (recurse)
1900 {
1901 ListCell *child;
1902 List *children;
1903
1904 children = find_all_inheritors(myrelid, lockmode, NULL);
1905
1906 foreach(child, children)
1907 {
1908 Oid childrelid = lfirst_oid(child);
1909
1910 if (list_member_oid(relids, childrelid))
1911 continue;
1912
1913 /* find_all_inheritors already got lock */
1914 rel = table_open(childrelid, NoLock);
1915
1916 /*
1917 * It is possible that the parent table has children that are
1918 * temp tables of other backends. We cannot safely access
1919 * such tables (because of buffering issues), and the best
1920 * thing to do is to silently ignore them. Note that this
1921 * check is the same as one of the checks done in
1922 * truncate_check_activity() called below, still it is kept
1923 * here for simplicity.
1924 */
1925 if (RELATION_IS_OTHER_TEMP(rel))
1926 {
1927 table_close(rel, lockmode);
1928 continue;
1929 }
1930
1931 /*
1932 * Inherited TRUNCATE commands perform access permission
1933 * checks on the parent table only. So we skip checking the
1934 * children's permissions and don't call
1935 * truncate_check_perms() here.
1936 */
1939
1940 rels = lappend(rels, rel);
1941 relids = lappend_oid(relids, childrelid);
1942
1943 /* Log this relation only if needed for logical decoding */
1945 relids_logged = lappend_oid(relids_logged, childrelid);
1946 }
1947 }
1948 else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1949 ereport(ERROR,
1950 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1951 errmsg("cannot truncate only a partitioned table"),
1952 errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1953 }
1954
1955 ExecuteTruncateGuts(rels, relids, relids_logged,
1956 stmt->behavior, stmt->restart_seqs, false);
1957
1958 /* And close the rels */
1959 foreach(cell, rels)
1960 {
1961 Relation rel = (Relation) lfirst(cell);
1962
1963 table_close(rel, NoLock);
1964 }
1965}
struct RelationData * Relation
Definition: genam.h:30
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:711
bool inh
Definition: primnodes.h:86
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2437
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2368
static void RangeVarCallbackForTruncate(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:19558
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs, bool run_as_table_owner)
Definition: tablecmds.c:1981

References AccessExclusiveLock, ereport, errcode(), errhint(), errmsg(), ERROR, ExecuteTruncateGuts(), find_all_inheritors(), RangeVar::inh, lappend(), lappend_oid(), lfirst, lfirst_oid, list_member_oid(), NIL, NoLock, RangeVarCallbackForTruncate(), RangeVarGetRelidExtended(), RelationData::rd_rel, RELATION_IS_OTHER_TEMP, RelationGetRelid, RelationIsLogicallyLogged, 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 
)

Definition at line 1981 of file tablecmds.c.

1986{
1987 List *rels;
1988 List *seq_relids = NIL;
1989 HTAB *ft_htab = NULL;
1990 EState *estate;
1991 ResultRelInfo *resultRelInfos;
1992 ResultRelInfo *resultRelInfo;
1993 SubTransactionId mySubid;
1994 ListCell *cell;
1995 Oid *logrelids;
1996
1997 /*
1998 * Check the explicitly-specified relations.
1999 *
2000 * In CASCADE mode, suck in all referencing relations as well. This
2001 * requires multiple iterations to find indirectly-dependent relations. At
2002 * each phase, we need to exclusive-lock new rels before looking for their
2003 * dependencies, else we might miss something. Also, we check each rel as
2004 * soon as we open it, to avoid a faux pas such as holding lock for a long
2005 * time on a rel we have no permissions for.
2006 */
2007 rels = list_copy(explicit_rels);
2008 if (behavior == DROP_CASCADE)
2009 {
2010 for (;;)
2011 {
2012 List *newrelids;
2013
2014 newrelids = heap_truncate_find_FKs(relids);
2015 if (newrelids == NIL)
2016 break; /* nothing else to add */
2017
2018 foreach(cell, newrelids)
2019 {
2020 Oid relid = lfirst_oid(cell);
2021 Relation rel;
2022
2023 rel = table_open(relid, AccessExclusiveLock);
2025 (errmsg("truncate cascades to table \"%s\"",
2027 truncate_check_rel(relid, rel->rd_rel);
2028 truncate_check_perms(relid, rel->rd_rel);
2030 rels = lappend(rels, rel);
2031 relids = lappend_oid(relids, relid);
2032
2033 /* Log this relation only if needed for logical decoding */
2035 relids_logged = lappend_oid(relids_logged, relid);
2036 }
2037 }
2038 }
2039
2040 /*
2041 * Check foreign key references. In CASCADE mode, this should be
2042 * unnecessary since we just pulled in all the references; but as a
2043 * cross-check, do it anyway if in an Assert-enabled build.
2044 */
2045#ifdef USE_ASSERT_CHECKING
2046 heap_truncate_check_FKs(rels, false);
2047#else
2048 if (behavior == DROP_RESTRICT)
2049 heap_truncate_check_FKs(rels, false);
2050#endif
2051
2052 /*
2053 * If we are asked to restart sequences, find all the sequences, lock them
2054 * (we need AccessExclusiveLock for ResetSequence), and check permissions.
2055 * We want to do this early since it's pointless to do all the truncation
2056 * work only to fail on sequence permissions.
2057 */
2058 if (restart_seqs)
2059 {
2060 foreach(cell, rels)
2061 {
2062 Relation rel = (Relation) lfirst(cell);
2063 List *seqlist = getOwnedSequences(RelationGetRelid(rel));
2064 ListCell *seqcell;
2065
2066 foreach(seqcell, seqlist)
2067 {
2068 Oid seq_relid = lfirst_oid(seqcell);
2069 Relation seq_rel;
2070
2071 seq_rel = relation_open(seq_relid, AccessExclusiveLock);
2072
2073 /* This check must match AlterSequence! */
2074 if (!object_ownercheck(RelationRelationId, seq_relid, GetUserId()))
2076 RelationGetRelationName(seq_rel));
2077
2078 seq_relids = lappend_oid(seq_relids, seq_relid);
2079
2080 relation_close(seq_rel, NoLock);
2081 }
2082 }
2083 }
2084
2085 /* Prepare to catch AFTER triggers. */
2087
2088 /*
2089 * To fire triggers, we'll need an EState as well as a ResultRelInfo for
2090 * each relation. We don't need to call ExecOpenIndices, though.
2091 *
2092 * We put the ResultRelInfos in the es_opened_result_relations list, even
2093 * though we don't have a range table and don't populate the
2094 * es_result_relations array. That's a bit bogus, but it's enough to make
2095 * ExecGetTriggerResultRel() find them.
2096 */
2097 estate = CreateExecutorState();
2098 resultRelInfos = (ResultRelInfo *)
2099 palloc(list_length(rels) * sizeof(ResultRelInfo));
2100 resultRelInfo = resultRelInfos;
2101 foreach(cell, rels)
2102 {
2103 Relation rel = (Relation) lfirst(cell);
2104
2105 InitResultRelInfo(resultRelInfo,
2106 rel,
2107 0, /* dummy rangetable index */
2108 NULL,
2109 0);
2111 lappend(estate->es_opened_result_relations, resultRelInfo);
2112 resultRelInfo++;
2113 }
2114
2115 /*
2116 * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
2117 * truncating (this is because one of them might throw an error). Also, if
2118 * we were to allow them to prevent statement execution, that would need
2119 * to be handled here.
2120 */
2121 resultRelInfo = resultRelInfos;
2122 foreach(cell, rels)
2123 {
2124 UserContext ucxt;
2125
2126 if (run_as_table_owner)
2127 SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2128 &ucxt);
2129 ExecBSTruncateTriggers(estate, resultRelInfo);
2130 if (run_as_table_owner)
2131 RestoreUserContext(&ucxt);
2132 resultRelInfo++;
2133 }
2134
2135 /*
2136 * OK, truncate each table.
2137 */
2138 mySubid = GetCurrentSubTransactionId();
2139
2140 foreach(cell, rels)
2141 {
2142 Relation rel = (Relation) lfirst(cell);
2143
2144 /* Skip partitioned tables as there is nothing to do */
2145 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2146 continue;
2147
2148 /*
2149 * Build the lists of foreign tables belonging to each foreign server
2150 * and pass each list to the foreign data wrapper's callback function,
2151 * so that each server can truncate its all foreign tables in bulk.
2152 * Each list is saved as a single entry in a hash table that uses the
2153 * server OID as lookup key.
2154 */
2155 if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2156 {
2158 bool found;
2159 ForeignTruncateInfo *ft_info;
2160
2161 /* First time through, initialize hashtable for foreign tables */
2162 if (!ft_htab)
2163 {
2164 HASHCTL hctl;
2165
2166 memset(&hctl, 0, sizeof(HASHCTL));
2167 hctl.keysize = sizeof(Oid);
2168 hctl.entrysize = sizeof(ForeignTruncateInfo);
2170
2171 ft_htab = hash_create("TRUNCATE for Foreign Tables",
2172 32, /* start small and extend */
2173 &hctl,
2175 }
2176
2177 /* Find or create cached entry for the foreign table */
2178 ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
2179 if (!found)
2180 ft_info->rels = NIL;
2181
2182 /*
2183 * Save the foreign table in the entry of the server that the
2184 * foreign table belongs to.
2185 */
2186 ft_info->rels = lappend(ft_info->rels, rel);
2187 continue;
2188 }
2189
2190 /*
2191 * Normally, we need a transaction-safe truncation here. However, if
2192 * the table was either created in the current (sub)transaction or has
2193 * a new relfilenumber in the current (sub)transaction, then we can
2194 * just truncate it in-place, because a rollback would cause the whole
2195 * table or the current physical file to be thrown away anyway.
2196 */
2197 if (rel->rd_createSubid == mySubid ||
2198 rel->rd_newRelfilelocatorSubid == mySubid)
2199 {
2200 /* Immediate, non-rollbackable truncation is OK */
2202 }
2203 else
2204 {
2205 Oid heap_relid;
2206 Oid toast_relid;
2207 ReindexParams reindex_params = {0};
2208
2209 /*
2210 * This effectively deletes all rows in the table, and may be done
2211 * in a serializable transaction. In that case we must record a
2212 * rw-conflict in to this transaction from each transaction
2213 * holding a predicate lock on the table.
2214 */
2216
2217 /*
2218 * Need the full transaction-safe pushups.
2219 *
2220 * Create a new empty storage file for the relation, and assign it
2221 * as the relfilenumber value. The old storage file is scheduled
2222 * for deletion at commit.
2223 */
2224 RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
2225
2226 heap_relid = RelationGetRelid(rel);
2227
2228 /*
2229 * The same for the toast table, if any.
2230 */
2231 toast_relid = rel->rd_rel->reltoastrelid;
2232 if (OidIsValid(toast_relid))
2233 {
2234 Relation toastrel = relation_open(toast_relid,
2236
2238 toastrel->rd_rel->relpersistence);
2239 table_close(toastrel, NoLock);
2240 }
2241
2242 /*
2243 * Reconstruct the indexes to match, and we're done.
2244 */
2246 &reindex_params);
2247 }
2248
2250 }
2251
2252 /* Now go through the hash table, and truncate foreign tables */
2253 if (ft_htab)
2254 {
2255 ForeignTruncateInfo *ft_info;
2256 HASH_SEQ_STATUS seq;
2257
2258 hash_seq_init(&seq, ft_htab);
2259
2260 PG_TRY();
2261 {
2262 while ((ft_info = hash_seq_search(&seq)) != NULL)
2263 {
2264 FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2265
2266 /* truncate_check_rel() has checked that already */
2267 Assert(routine->ExecForeignTruncate != NULL);
2268
2269 routine->ExecForeignTruncate(ft_info->rels,
2270 behavior,
2271 restart_seqs);
2272 }
2273 }
2274 PG_FINALLY();
2275 {
2276 hash_destroy(ft_htab);
2277 }
2278 PG_END_TRY();
2279 }
2280
2281 /*
2282 * Restart owned sequences if we were asked to.
2283 */
2284 foreach(cell, seq_relids)
2285 {
2286 Oid seq_relid = lfirst_oid(cell);
2287
2288 ResetSequence(seq_relid);
2289 }
2290
2291 /*
2292 * Write a WAL record to allow this set of actions to be logically
2293 * decoded.
2294 *
2295 * Assemble an array of relids so we can write a single WAL record for the
2296 * whole action.
2297 */
2298 if (relids_logged != NIL)
2299 {
2300 xl_heap_truncate xlrec;
2301 int i = 0;
2302
2303 /* should only get here if effective_wal_level is 'logical' */
2305
2306 logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
2307 foreach(cell, relids_logged)
2308 logrelids[i++] = lfirst_oid(cell);
2309
2310 xlrec.dbId = MyDatabaseId;
2311 xlrec.nrelids = list_length(relids_logged);
2312 xlrec.flags = 0;
2313 if (behavior == DROP_CASCADE)
2314 xlrec.flags |= XLH_TRUNCATE_CASCADE;
2315 if (restart_seqs)
2317
2320 XLogRegisterData(logrelids, list_length(relids_logged) * sizeof(Oid));
2321
2323
2324 (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
2325 }
2326
2327 /*
2328 * Process all AFTER STATEMENT TRUNCATE triggers.
2329 */
2330 resultRelInfo = resultRelInfos;
2331 foreach(cell, rels)
2332 {
2333 UserContext ucxt;
2334
2335 if (run_as_table_owner)
2336 SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2337 &ucxt);
2338 ExecASTruncateTriggers(estate, resultRelInfo);
2339 if (run_as_table_owner)
2340 RestoreUserContext(&ucxt);
2341 resultRelInfo++;
2342 }
2343
2344 /* Handle queued AFTER triggers */
2345 AfterTriggerEndQuery(estate);
2346
2347 /* We can clean up the EState now */
2348 FreeExecutorState(estate);
2349
2350 /*
2351 * Close any rels opened by CASCADE (can't do this while EState still
2352 * holds refs)
2353 */
2354 rels = list_difference_ptr(rels, explicit_rels);
2355 foreach(cell, rels)
2356 {
2357 Relation rel = (Relation) lfirst(cell);
2358
2359 table_close(rel, NoLock);
2360 }
2361}
uint32 SubTransactionId
Definition: c.h:675
void ResetSequence(Oid seq_relid)
Definition: sequence.c:255
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:358
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1415
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1380
#define PG_TRY(...)
Definition: elog.h:372
#define PG_END_TRY(...)
Definition: elog.h:397
#define PG_FINALLY(...)
Definition: elog.h:389
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition: execMain.c:1243
void FreeExecutorState(EState *estate)
Definition: execUtils.c:192
EState * CreateExecutorState(void)
Definition: execUtils.c:88
struct ResultRelInfo ResultRelInfo
FdwRoutine * GetFdwRoutineByServerId(Oid serverid)
Definition: foreign.c:378
Oid GetForeignServerIdByRelId(Oid relid)
Definition: foreign.c:356
Oid MyDatabaseId
Definition: globals.c:94
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3767
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3672
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3628
#define XLOG_HEAP_TRUNCATE
Definition: heapam_xlog.h:36
#define XLH_TRUNCATE_RESTART_SEQS
Definition: heapam_xlog.h:127
#define SizeOfHeapTruncate
Definition: heapam_xlog.h:142
#define XLH_TRUNCATE_CASCADE
Definition: heapam_xlog.h:126
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
bool reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, const ReindexParams *params)
Definition: index.c:3946
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:159
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:1387
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
@ DROP_CASCADE
Definition: parsenodes.h:2426
@ DROP_RESTRICT
Definition: parsenodes.h:2425
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2389
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:936
void pgstat_count_truncate(Relation rel)
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4417
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition: relcache.c:3768
List * es_opened_result_relations
Definition: execnodes.h:688
ExecForeignTruncate_function ExecForeignTruncate
Definition: fdwapi.h:263
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
MemoryContext hcxt
Definition: hsearch.h:86
Definition: dynahash.c:222
SubTransactionId rd_newRelfilelocatorSubid
Definition: rel.h:104
SubTransactionId rd_createSubid
Definition: rel.h:103
Relation ri_RelationDesc
Definition: execnodes.h:480
struct ForeignTruncateInfo ForeignTruncateInfo
static void truncate_check_perms(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2419
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3280
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3327
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:5124
void AfterTriggerBeginQuery(void)
Definition: trigger.c:5104
void SwitchToUntrustedUser(Oid userid, UserContext *context)
Definition: usercontext.c:33
void RestoreUserContext(UserContext *context)
Definition: usercontext.c:87
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:792
#define XLogLogicalInfoActive()
Definition: xlog.h:136
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:165
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:478
void XLogRegisterData(const void *data, uint32 len)
Definition: xloginsert.c:368
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:460
void XLogBeginInsert(void)
Definition: xloginsert.c:152

References AccessExclusiveLock, aclcheck_error(), ACLCHECK_NOT_OWNER, AfterTriggerBeginQuery(), AfterTriggerEndQuery(), Assert(), CheckTableForSerializableConflictIn(), CreateExecutorState(), CurrentMemoryContext, xl_heap_truncate::dbId, DROP_CASCADE, DROP_RESTRICT, HASHCTL::entrysize, ereport, errmsg(), EState::es_opened_result_relations, ExecASTruncateTriggers(), ExecBSTruncateTriggers(), FdwRoutine::ExecForeignTruncate, xl_heap_truncate::flags, 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, xl_heap_truncate::nrelids, 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(), ForeignTruncateInfo::rels, ResetSequence(), RestoreUserContext(), ResultRelInfo::ri_RelationDesc, ForeignTruncateInfo::serverid, 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 
)

Definition at line 6965 of file tablecmds.c.

6967{
6968 Relation depRel;
6969 ScanKeyData key[2];
6970 SysScanDesc depScan;
6971 HeapTuple depTup;
6972
6973 /* since this function recurses, it could be driven to stack overflow */
6975
6976 /*
6977 * We scan pg_depend to find those things that depend on the given type.
6978 * (We assume we can ignore refobjsubid for a type.)
6979 */
6980 depRel = table_open(DependRelationId, AccessShareLock);
6981
6982 ScanKeyInit(&key[0],
6983 Anum_pg_depend_refclassid,
6984 BTEqualStrategyNumber, F_OIDEQ,
6985 ObjectIdGetDatum(TypeRelationId));
6986 ScanKeyInit(&key[1],
6987 Anum_pg_depend_refobjid,
6988 BTEqualStrategyNumber, F_OIDEQ,
6989 ObjectIdGetDatum(typeOid));
6990
6991 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6992 NULL, 2, key);
6993
6994 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6995 {
6996 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6997 Relation rel;
6998 TupleDesc tupleDesc;
7000
7001 /* Check for directly dependent types */
7002 if (pg_depend->classid == TypeRelationId)
7003 {
7004 /*
7005 * This must be an array, domain, or range containing the given
7006 * type, so recursively check for uses of this type. Note that
7007 * any error message will mention the original type not the
7008 * container; this is intentional.
7009 */
7010 find_composite_type_dependencies(pg_depend->objid,
7011 origRelation, origTypeName);
7012 continue;
7013 }
7014
7015 /* Else, ignore dependees that aren't relations */
7016 if (pg_depend->classid != RelationRelationId)
7017 continue;
7018
7019 rel = relation_open(pg_depend->objid, AccessShareLock);
7020 tupleDesc = RelationGetDescr(rel);
7021
7022 /*
7023 * If objsubid identifies a specific column, refer to that in error
7024 * messages. Otherwise, search to see if there's a user column of the
7025 * type. (We assume system columns are never of interesting types.)
7026 * The search is needed because an index containing an expression
7027 * column of the target type will just be recorded as a whole-relation
7028 * dependency. If we do not find a column of the type, the dependency
7029 * must indicate that the type is transiently referenced in an index
7030 * expression but not stored on disk, which we assume is OK, just as
7031 * we do for references in views. (It could also be that the target
7032 * type is embedded in some container type that is stored in an index
7033 * column, but the previous recursion should catch such cases.)
7034 */
7035 if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
7036 att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
7037 else
7038 {
7039 att = NULL;
7040 for (int attno = 1; attno <= tupleDesc->natts; attno++)
7041 {
7042 att = TupleDescAttr(tupleDesc, attno - 1);
7043 if (att->atttypid == typeOid && !att->attisdropped)
7044 break;
7045 att = NULL;
7046 }
7047 if (att == NULL)
7048 {
7049 /* No such column, so assume OK */
7051 continue;
7052 }
7053 }
7054
7055 /*
7056 * We definitely should reject if the relation has storage. If it's
7057 * partitioned, then perhaps we don't have to reject: if there are
7058 * partitions then we'll fail when we find one, else there is no
7059 * stored data to worry about. However, it's possible that the type
7060 * change would affect conclusions about whether the type is sortable
7061 * or hashable and thus (if it's a partitioning column) break the
7062 * partitioning rule. For now, reject for partitioned rels too.
7063 */
7064 if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
7065 RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
7066 {
7067 if (origTypeName)
7068 ereport(ERROR,
7069 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7070 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
7071 origTypeName,
7073 NameStr(att->attname))));
7074 else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
7075 ereport(ERROR,
7076 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7077 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
7078 RelationGetRelationName(origRelation),
7080 NameStr(att->attname))));
7081 else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
7082 ereport(ERROR,
7083 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7084 errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
7085 RelationGetRelationName(origRelation),
7087 NameStr(att->attname))));
7088 else
7089 ereport(ERROR,
7090 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7091 errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
7092 RelationGetRelationName(origRelation),
7094 NameStr(att->attname))));
7095 }
7096 else if (OidIsValid(rel->rd_rel->reltype))
7097 {
7098 /*
7099 * A view or composite type itself isn't a problem, but we must
7100 * recursively check for indirect dependencies via its rowtype.
7101 */
7103 origRelation, origTypeName);
7104 }
7105
7107 }
7108
7109 systable_endscan(depScan);
7110
7112}
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:388
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
void check_stack_depth(void)
Definition: stack_depth.c:95
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:6965

References AccessShareLock, BTEqualStrategyNumber, check_stack_depth(), ereport, errcode(), errmsg(), ERROR, find_composite_type_dependencies(), GETSTRUCT(), HeapTupleIsValid, sort-test::key, NameStr, TupleDescData::natts, 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 
)

Definition at line 20087 of file tablecmds.c.

20089{
20090 List *existConstraint = NIL;
20091 TupleConstr *constr = RelationGetDescr(scanrel)->constr;
20092 int i;
20093
20094 if (constr && constr->has_not_null)
20095 {
20096 int natts = scanrel->rd_att->natts;
20097
20098 for (i = 1; i <= natts; i++)
20099 {
20100 CompactAttribute *att = TupleDescCompactAttr(scanrel->rd_att, i - 1);
20101
20102 /* invalid not-null constraint must be ignored here */
20103 if (att->attnullability == ATTNULLABLE_VALID && !att->attisdropped)
20104 {
20105 Form_pg_attribute wholeatt = TupleDescAttr(scanrel->rd_att, i - 1);
20106 NullTest *ntest = makeNode(NullTest);
20107
20108 ntest->arg = (Expr *) makeVar(1,
20109 i,
20110 wholeatt->atttypid,
20111 wholeatt->atttypmod,
20112 wholeatt->attcollation,
20113 0);
20114 ntest->nulltesttype = IS_NOT_NULL;
20115
20116 /*
20117 * argisrow=false is correct even for a composite column,
20118 * because attnotnull does not represent a SQL-spec IS NOT
20119 * NULL test in such a case, just IS DISTINCT FROM NULL.
20120 */
20121 ntest->argisrow = false;
20122 ntest->location = -1;
20123 existConstraint = lappend(existConstraint, ntest);
20124 }
20125 }
20126 }
20127
20128 return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
20129}
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
@ IS_NOT_NULL
Definition: primnodes.h:1977
bool attisdropped
Definition: tupdesc.h:77
char attnullability
Definition: tupdesc.h:79
NullTestType nulltesttype
Definition: primnodes.h:1984
ParseLoc location
Definition: primnodes.h:1987
Expr * arg
Definition: primnodes.h:1983
TupleDesc rd_att
Definition: rel.h:112
bool has_not_null
Definition: tupdesc.h:45
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:20142
#define ATTNULLABLE_VALID
Definition: tupdesc.h:86
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:175

References NullTest::arg, CompactAttribute::attisdropped, CompactAttribute::attnullability, ATTNULLABLE_VALID, ConstraintImpliedByRelConstraint(), TupleConstr::has_not_null, i, IS_NOT_NULL, lappend(), NullTest::location, makeNode, makeVar(), TupleDescData::natts, NIL, NullTest::nulltesttype, 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  )

Definition at line 19348 of file tablecmds.c.

19349{
19350 ListCell *l;
19351 List *oids_to_truncate = NIL;
19352 List *oids_to_drop = NIL;
19353
19354 foreach(l, on_commits)
19355 {
19356 OnCommitItem *oc = (OnCommitItem *) lfirst(l);
19357
19358 /* Ignore entry if already dropped in this xact */
19360 continue;
19361
19362 switch (oc->oncommit)
19363 {
19364 case ONCOMMIT_NOOP:
19366 /* Do nothing (there shouldn't be such entries, actually) */
19367 break;
19369
19370 /*
19371 * If this transaction hasn't accessed any temporary
19372 * relations, we can skip truncating ON COMMIT DELETE ROWS
19373 * tables, as they must still be empty.
19374 */
19376 oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
19377 break;
19378 case ONCOMMIT_DROP:
19379 oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
19380 break;
19381 }
19382 }
19383
19384 /*
19385 * Truncate relations before dropping so that all dependencies between
19386 * relations are removed after they are worked on. Doing it like this
19387 * might be a waste as it is possible that a relation being truncated will
19388 * be dropped anyway due to its parent being dropped, but this makes the
19389 * code more robust because of not having to re-check that the relation
19390 * exists at truncation time.
19391 */
19392 if (oids_to_truncate != NIL)
19393 heap_truncate(oids_to_truncate);
19394
19395 if (oids_to_drop != NIL)
19396 {
19397 ObjectAddresses *targetObjects = new_object_addresses();
19398
19399 foreach(l, oids_to_drop)
19400 {
19401 ObjectAddress object;
19402
19403 object.classId = RelationRelationId;
19404 object.objectId = lfirst_oid(l);
19405 object.objectSubId = 0;
19406
19407 Assert(!object_address_present(&object, targetObjects));
19408
19409 add_exact_object_address(&object, targetObjects);
19410 }
19411
19412 /*
19413 * Object deletion might involve toast table access (to clean up
19414 * toasted catalog entries), so ensure we have a valid snapshot.
19415 */
19417
19418 /*
19419 * Since this is an automatic drop, rather than one directly initiated
19420 * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
19421 */
19424
19426
19427#ifdef USE_ASSERT_CHECKING
19428
19429 /*
19430 * Note that table deletion will call remove_on_commit_action, so the
19431 * entry should get marked as deleted.
19432 */
19433 foreach(l, on_commits)
19434 {
19435 OnCommitItem *oc = (OnCommitItem *) lfirst(l);
19436
19437 if (oc->oncommit != ONCOMMIT_DROP)
19438 continue;
19439
19441 }
19442#endif
19443 }
19444}
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:383
#define PERFORM_DELETION_QUIETLY
Definition: dependency.h:94
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:92
void heap_truncate(List *relids)
Definition: heap.c:3587
@ ONCOMMIT_DELETE_ROWS
Definition: primnodes.h:60
@ ONCOMMIT_PRESERVE_ROWS
Definition: primnodes.h:59
@ ONCOMMIT_DROP
Definition: primnodes.h:61
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:272
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:682
void PopActiveSnapshot(void)
Definition: snapmgr.c:775
OnCommitAction oncommit
Definition: tablecmds.c:119
int MyXactFlags
Definition: xact.c:137
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:103

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

Referenced by CommitTransaction(), and PrepareTransaction().

◆ RangeVarCallbackMaintainsTable()

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

Definition at line 19522 of file tablecmds.c.

19524{
19525 char relkind;
19526 AclResult aclresult;
19527
19528 /* Nothing to do if the relation was not found. */
19529 if (!OidIsValid(relId))
19530 return;
19531
19532 /*
19533 * If the relation does exist, check whether it's an index. But note that
19534 * the relation might have been dropped between the time we did the name
19535 * lookup and now. In that case, there's nothing to do.
19536 */
19537 relkind = get_rel_relkind(relId);
19538 if (!relkind)
19539 return;
19540 if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
19541 relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
19542 ereport(ERROR,
19543 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
19544 errmsg("\"%s\" is not a table or materialized view", relation->relname)));
19545
19546 /* Check permissions */
19547 aclresult = pg_class_aclcheck(relId, GetUserId(), ACL_MAINTAIN);
19548 if (aclresult != ACLCHECK_OK)
19549 aclcheck_error(aclresult,
19551 relation->relname);
19552}
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4039
#define ACL_MAINTAIN
Definition: parsenodes.h:90
char * relname
Definition: primnodes.h:83

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

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

◆ RangeVarCallbackOwnsRelation()

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

Definition at line 19582 of file tablecmds.c.

19584{
19585 HeapTuple tuple;
19586
19587 /* Nothing to do if the relation was not found. */
19588 if (!OidIsValid(relId))
19589 return;
19590
19591 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
19592 if (!HeapTupleIsValid(tuple)) /* should not happen */
19593 elog(ERROR, "cache lookup failed for relation %u", relId);
19594
19595 if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
19597 relation->relname);
19598
19599 if (!allowSystemTableMods &&
19600 IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
19601 ereport(ERROR,
19602 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
19603 errmsg("permission denied: \"%s\" is a system catalog",
19604 relation->relname)));
19605
19606 ReleaseSysCache(tuple);
19607}
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:86

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

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

◆ register_on_commit_action()

void register_on_commit_action ( Oid  relid,
OnCommitAction  action 
)

Definition at line 19289 of file tablecmds.c.

19290{
19291 OnCommitItem *oc;
19292 MemoryContext oldcxt;
19293
19294 /*
19295 * We needn't bother registering the relation unless there is an ON COMMIT
19296 * action we need to take.
19297 */
19299 return;
19300
19302
19304 oc->relid = relid;
19305 oc->oncommit = action;
19308
19309 /*
19310 * We use lcons() here so that ON COMMIT actions are processed in reverse
19311 * order of registration. That might not be essential but it seems
19312 * reasonable.
19313 */
19315
19316 MemoryContextSwitchTo(oldcxt);
19317}
List * lcons(void *datum, List *list)
Definition: list.c:495
MemoryContext CacheMemoryContext
Definition: mcxt.c:169
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124

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

Referenced by heap_create_with_catalog().

◆ remove_on_commit_action()

void remove_on_commit_action ( Oid  relid)

Definition at line 19325 of file tablecmds.c.

19326{
19327 ListCell *l;
19328
19329 foreach(l, on_commits)
19330 {
19331 OnCommitItem *oc = (OnCommitItem *) lfirst(l);
19332
19333 if (oc->relid == relid)
19334 {
19336 break;
19337 }
19338 }
19339}

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

Referenced by heap_drop_with_catalog().

◆ RemoveRelations()

void RemoveRelations ( DropStmt drop)

Definition at line 1534 of file tablecmds.c.

1535{
1536 ObjectAddresses *objects;
1537 char relkind;
1538 ListCell *cell;
1539 int flags = 0;
1540 LOCKMODE lockmode = AccessExclusiveLock;
1541
1542 /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1543 if (drop->concurrent)
1544 {
1545 /*
1546 * Note that for temporary relations this lock may get upgraded later
1547 * on, but as no other session can access a temporary relation, this
1548 * is actually fine.
1549 */
1550 lockmode = ShareUpdateExclusiveLock;
1551 Assert(drop->removeType == OBJECT_INDEX);
1552 if (list_length(drop->objects) != 1)
1553 ereport(ERROR,
1554 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1555 errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1556 if (drop->behavior == DROP_CASCADE)
1557 ereport(ERROR,
1558 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1559 errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1560 }
1561
1562 /*
1563 * First we identify all the relations, then we delete them in a single
1564 * performMultipleDeletions() call. This is to avoid unwanted DROP
1565 * RESTRICT errors if one of the relations depends on another.
1566 */
1567
1568 /* Determine required relkind */
1569 switch (drop->removeType)
1570 {
1571 case OBJECT_TABLE:
1572 relkind = RELKIND_RELATION;
1573 break;
1574
1575 case OBJECT_INDEX:
1576 relkind = RELKIND_INDEX;
1577 break;
1578
1579 case OBJECT_SEQUENCE:
1580 relkind = RELKIND_SEQUENCE;
1581 break;
1582
1583 case OBJECT_VIEW:
1584 relkind = RELKIND_VIEW;
1585 break;
1586
1587 case OBJECT_MATVIEW:
1588 relkind = RELKIND_MATVIEW;
1589 break;
1590
1592 relkind = RELKIND_FOREIGN_TABLE;
1593 break;
1594
1595 default:
1596 elog(ERROR, "unrecognized drop object type: %d",
1597 (int) drop->removeType);
1598 relkind = 0; /* keep compiler quiet */
1599 break;
1600 }
1601
1602 /* Lock and validate each relation; build a list of object addresses */
1603 objects = new_object_addresses();
1604
1605 foreach(cell, drop->objects)
1606 {
1607 RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1608 Oid relOid;
1609 ObjectAddress obj;
1611
1612 /*
1613 * These next few steps are a great deal like relation_openrv, but we
1614 * don't bother building a relcache entry since we don't need it.
1615 *
1616 * Check for shared-cache-inval messages before trying to access the
1617 * relation. This is needed to cover the case where the name
1618 * identifies a rel that has been dropped and recreated since the
1619 * start of our transaction: if we don't flush the old syscache entry,
1620 * then we'll latch onto that entry and suffer an error later.
1621 */
1623
1624 /* Look up the appropriate relation using namespace search. */
1625 state.expected_relkind = relkind;
1626 state.heap_lockmode = drop->concurrent ?
1628 /* We must initialize these fields to show that no locks are held: */
1629 state.heapOid = InvalidOid;
1630 state.partParentOid = InvalidOid;
1631
1632 relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1634 &state);
1635
1636 /* Not there? */
1637 if (!OidIsValid(relOid))
1638 {
1639 DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1640 continue;
1641 }
1642
1643 /*
1644 * Decide if concurrent mode needs to be used here or not. The
1645 * callback retrieved the rel's persistence for us.
1646 */
1647 if (drop->concurrent &&
1648 state.actual_relpersistence != RELPERSISTENCE_TEMP)
1649 {
1650 Assert(list_length(drop->objects) == 1 &&
1651 drop->removeType == OBJECT_INDEX);
1653 }
1654
1655 /*
1656 * Concurrent index drop cannot be used with partitioned indexes,
1657 * either.
1658 */
1659 if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1660 state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1661 ereport(ERROR,
1662 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1663 errmsg("cannot drop partitioned index \"%s\" concurrently",
1664 rel->relname)));
1665
1666 /*
1667 * If we're told to drop a partitioned index, we must acquire lock on
1668 * all the children of its parent partitioned table before proceeding.
1669 * Otherwise we'd try to lock the child index partitions before their
1670 * tables, leading to potential deadlock against other sessions that
1671 * will lock those objects in the other order.
1672 */
1673 if (state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1674 (void) find_all_inheritors(state.heapOid,
1675 state.heap_lockmode,
1676 NULL);
1677
1678 /* OK, we're ready to delete this one */
1679 obj.classId = RelationRelationId;
1680 obj.objectId = relOid;
1681 obj.objectSubId = 0;
1682
1683 add_exact_object_address(&obj, objects);
1684 }
1685
1686 performMultipleDeletions(objects, drop->behavior, flags);
1687
1688 free_object_addresses(objects);
1689}
#define PERFORM_DELETION_CONCURRENTLY
Definition: dependency.h:93
void AcceptInvalidationMessages(void)
Definition: inval.c:930
RangeVar * makeRangeVarFromNameList(const List *names)
Definition: namespace.c:3624
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2370
@ OBJECT_VIEW
Definition: parsenodes.h:2403
bool missing_ok
Definition: parsenodes.h:3366
List * objects
Definition: parsenodes.h:3363
ObjectType removeType
Definition: parsenodes.h:3364
bool concurrent
Definition: parsenodes.h:3367
DropBehavior behavior
Definition: parsenodes.h:3365
Definition: regguts.h:323
static void DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
Definition: tablecmds.c:1459
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:1698

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

Referenced by ExecDropStmt().

◆ renameatt()

ObjectAddress renameatt ( RenameStmt stmt)

Definition at line 4007 of file tablecmds.c.

4008{
4009 Oid relid;
4011 ObjectAddress address;
4012
4013 /* lock level taken here should match renameatt_internal */
4015 stmt->missing_ok ? RVR_MISSING_OK : 0,
4017 NULL);
4018
4019 if (!OidIsValid(relid))
4020 {
4022 (errmsg("relation \"%s\" does not exist, skipping",
4023 stmt->relation->relname)));
4024 return InvalidObjectAddress;
4025 }
4026
4027 attnum =
4028 renameatt_internal(relid,
4029 stmt->subname, /* old att name */
4030 stmt->newname, /* new att name */
4031 stmt->relation->inh, /* recursive? */
4032 false, /* recursing? */
4033 0, /* expected inhcount */
4034 stmt->behavior);
4035
4036 ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
4037
4038 return address;
4039}
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:3842
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3987

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

Referenced by ExecRenameStmt().

◆ RenameConstraint()

ObjectAddress RenameConstraint ( RenameStmt stmt)

Definition at line 4154 of file tablecmds.c.

4155{
4156 Oid relid = InvalidOid;
4157 Oid typid = InvalidOid;
4158
4159 if (stmt->renameType == OBJECT_DOMCONSTRAINT)
4160 {
4161 Relation rel;
4162 HeapTuple tup;
4163
4164 typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
4165 rel = table_open(TypeRelationId, RowExclusiveLock);
4166 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
4167 if (!HeapTupleIsValid(tup))
4168 elog(ERROR, "cache lookup failed for type %u", typid);
4169 checkDomainOwner(tup);
4170 ReleaseSysCache(tup);
4171 table_close(rel, NoLock);
4172 }
4173 else
4174 {
4175 /* lock level taken here should match rename_constraint_internal */
4177 stmt->missing_ok ? RVR_MISSING_OK : 0,
4179 NULL);
4180 if (!OidIsValid(relid))
4181 {
4183 (errmsg("relation \"%s\" does not exist, skipping",
4184 stmt->relation->relname)));
4185 return InvalidObjectAddress;
4186 }
4187 }
4188
4189 return
4190 rename_constraint_internal(relid, typid,
4191 stmt->subname,
4192 stmt->newname,
4193 (stmt->relation &&
4194 stmt->relation->inh), /* recursive? */
4195 false, /* recursing? */
4196 0 /* expected inhcount */ );
4197}
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:531
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2365
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:4045
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3499

References AccessExclusiveLock, castNode, checkDomainOwner(), elog, ereport, errmsg(), ERROR, 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)

Definition at line 4204 of file tablecmds.c.

4205{
4206 bool is_index_stmt = stmt->renameType == OBJECT_INDEX;
4207 Oid relid;
4208 ObjectAddress address;
4209
4210 /*
4211 * Grab an exclusive lock on the target table, index, sequence, view,
4212 * materialized view, or foreign table, which we will NOT release until
4213 * end of transaction.
4214 *
4215 * Lock level used here should match RenameRelationInternal, to avoid lock
4216 * escalation. However, because ALTER INDEX can be used with any relation
4217 * type, we mustn't believe without verification.
4218 */
4219 for (;;)
4220 {
4221 LOCKMODE lockmode;
4222 char relkind;
4223 bool obj_is_index;
4224
4225 lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
4226
4227 relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
4228 stmt->missing_ok ? RVR_MISSING_OK : 0,
4230 stmt);
4231
4232 if (!OidIsValid(relid))
4233 {
4235 (errmsg("relation \"%s\" does not exist, skipping",
4236 stmt->relation->relname)));
4237 return InvalidObjectAddress;
4238 }
4239
4240 /*
4241 * We allow mismatched statement and object types (e.g., ALTER INDEX
4242 * to rename a table), but we might've used the wrong lock level. If
4243 * that happens, retry with the correct lock level. We don't bother
4244 * if we already acquired AccessExclusiveLock with an index, however.
4245 */
4246 relkind = get_rel_relkind(relid);
4247 obj_is_index = (relkind == RELKIND_INDEX ||
4248 relkind == RELKIND_PARTITIONED_INDEX);
4249 if (obj_is_index || is_index_stmt == obj_is_index)
4250 break;
4251
4252 UnlockRelationOid(relid, lockmode);
4253 is_index_stmt = obj_is_index;
4254 }
4255
4256 /* Do the work */
4257 RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
4258
4259 ObjectAddressSet(address, RelationRelationId, relid);
4260
4261 return address;
4262}
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:4268

References AccessExclusiveLock, ereport, errmsg(), 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 
)

Definition at line 4268 of file tablecmds.c.

4269{
4270 Relation targetrelation;
4271 Relation relrelation; /* for RELATION relation */
4272 ItemPointerData otid;
4273 HeapTuple reltup;
4274 Form_pg_class relform;
4275 Oid namespaceId;
4276
4277 /*
4278 * Grab a lock on the target relation, which we will NOT release until end
4279 * of transaction. We need at least a self-exclusive lock so that
4280 * concurrent DDL doesn't overwrite the rename if they start updating
4281 * while still seeing the old version. The lock also guards against
4282 * triggering relcache reloads in concurrent sessions, which might not
4283 * handle this information changing under them. For indexes, we can use a
4284 * reduced lock level because RelationReloadIndexInfo() handles indexes
4285 * specially.
4286 */
4287 targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
4288 namespaceId = RelationGetNamespace(targetrelation);
4289
4290 /*
4291 * Find relation's pg_class tuple, and make sure newrelname isn't in use.
4292 */
4293 relrelation = table_open(RelationRelationId, RowExclusiveLock);
4294
4295 reltup = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(myrelid));
4296 if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4297 elog(ERROR, "cache lookup failed for relation %u", myrelid);
4298 otid = reltup->t_self;
4299 relform = (Form_pg_class) GETSTRUCT(reltup);
4300
4301 if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
4302 ereport(ERROR,
4303 (errcode(ERRCODE_DUPLICATE_TABLE),
4304 errmsg("relation \"%s\" already exists",
4305 newrelname)));
4306
4307 /*
4308 * RenameRelation is careful not to believe the caller's idea of the
4309 * relation kind being handled. We don't have to worry about this, but
4310 * let's not be totally oblivious to it. We can process an index as
4311 * not-an-index, but not the other way around.
4312 */
4313 Assert(!is_index ||
4314 is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4315 targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
4316
4317 /*
4318 * Update pg_class tuple with new relname. (Scribbling on reltup is OK
4319 * because it's a copy...)
4320 */
4321 namestrcpy(&(relform->relname), newrelname);
4322
4323 CatalogTupleUpdate(relrelation, &otid, reltup);
4324 UnlockTuple(relrelation, &otid, InplaceUpdateTupleLock);
4325
4326 InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
4327 InvalidOid, is_internal);
4328
4329 heap_freetuple(reltup);
4330 table_close(relrelation, RowExclusiveLock);
4331
4332 /*
4333 * Also rename the associated type, if any.
4334 */
4335 if (OidIsValid(targetrelation->rd_rel->reltype))
4336 RenameTypeInternal(targetrelation->rd_rel->reltype,
4337 newrelname, namespaceId);
4338
4339 /*
4340 * Also rename the associated constraint, if any.
4341 */
4342 if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4343 targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4344 {
4345 Oid constraintId = get_index_constraint(myrelid);
4346
4347 if (OidIsValid(constraintId))
4348 RenameConstraintById(constraintId, newrelname);
4349 }
4350
4351 /*
4352 * Close rel, but keep lock!
4353 */
4354 relation_close(targetrelation, NoLock);
4355}
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
Definition: objectaccess.h:200
void RenameConstraintById(Oid conId, const char *newname)
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:988
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:763

References AccessExclusiveLock, Assert(), CatalogTupleUpdate(), elog, ereport, errcode(), errmsg(), ERROR, get_index_constraint(), get_relname_relid(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, InplaceUpdateTupleLock, InvalidOid, InvokeObjectPostAlterHookArg, namestrcpy(), NoLock, ObjectIdGetDatum(), OidIsValid, RelationData::rd_rel, relation_close(), relation_open(), RelationGetNamespace, RenameConstraintById(), RenameTypeInternal(), RowExclusiveLock, SearchSysCacheLockedCopy1(), ShareUpdateExclusiveLock, HeapTupleData::t_self, 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)

Definition at line 4361 of file tablecmds.c.

4362{
4363 Relation relrelation; /* for RELATION relation */
4364 HeapTuple reltup;
4365 Form_pg_class relform;
4366
4367 /*
4368 * Find relation's pg_class tuple.
4369 */
4370 relrelation = table_open(RelationRelationId, RowExclusiveLock);
4371
4372 reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4373 if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4374 elog(ERROR, "cache lookup failed for relation %u", myrelid);
4375 relform = (Form_pg_class) GETSTRUCT(reltup);
4376
4377 /*
4378 * Update pg_class tuple.
4379 */
4380 relform->relrewrite = InvalidOid;
4381
4382 CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4383
4384 heap_freetuple(reltup);
4385 table_close(relrelation, RowExclusiveLock);
4386}
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91

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

Referenced by finish_heap_swap().

◆ SetRelationHasSubclass()

void SetRelationHasSubclass ( Oid  relationId,
bool  relhassubclass 
)

Definition at line 3645 of file tablecmds.c.

3646{
3647 Relation relationRelation;
3648 HeapTuple tuple;
3649 Form_pg_class classtuple;
3650
3652 ShareUpdateExclusiveLock, false) ||
3653 CheckRelationOidLockedByMe(relationId,
3654 ShareRowExclusiveLock, true));
3655
3656 /*
3657 * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3658 */
3659 relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3660 tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3661 if (!HeapTupleIsValid(tuple))
3662 elog(ERROR, "cache lookup failed for relation %u", relationId);
3663 classtuple = (Form_pg_class) GETSTRUCT(tuple);
3664
3665 if (classtuple->relhassubclass != relhassubclass)
3666 {
3667 classtuple->relhassubclass = relhassubclass;
3668 CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3669 }
3670 else
3671 {
3672 /* no need to change tuple, but force relcache rebuild anyway */
3674 }
3675
3676 heap_freetuple(tuple);
3677 table_close(relationRelation, RowExclusiveLock);
3678}
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1669
bool CheckRelationOidLockedByMe(Oid relid, LOCKMODE lockmode, bool orstronger)
Definition: lmgr.c:351

References Assert(), CacheInvalidateRelcacheByTuple(), CatalogTupleUpdate(), CheckRelationOidLockedByMe(), elog, ERROR, 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 
)

Definition at line 3748 of file tablecmds.c.

3751{
3752 Relation pg_class;
3753 HeapTuple tuple;
3754 ItemPointerData otid;
3755 Form_pg_class rd_rel;
3756 Oid reloid = RelationGetRelid(rel);
3757
3758 Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3759
3760 /* Get a modifiable copy of the relation's pg_class row. */
3761 pg_class = table_open(RelationRelationId, RowExclusiveLock);
3762
3763 tuple = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(reloid));
3764 if (!HeapTupleIsValid(tuple))
3765 elog(ERROR, "cache lookup failed for relation %u", reloid);
3766 otid = tuple->t_self;
3767 rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3768
3769 /* Update the pg_class row. */
3770 rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3771 InvalidOid : newTableSpaceId;
3772 if (RelFileNumberIsValid(newRelFilenumber))
3773 rd_rel->relfilenode = newRelFilenumber;
3774 CatalogTupleUpdate(pg_class, &otid, tuple);
3775 UnlockTuple(pg_class, &otid, InplaceUpdateTupleLock);
3776
3777 /*
3778 * Record dependency on tablespace. This is only required for relations
3779 * that have no physical storage.
3780 */
3781 if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3782 changeDependencyOnTablespace(RelationRelationId, reloid,
3783 rd_rel->reltablespace);
3784
3785 heap_freetuple(tuple);
3786 table_close(pg_class, RowExclusiveLock);
3787}
void changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId)
Definition: pg_shdepend.c:391
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
Definition: tablecmds.c:3691

References Assert(), CatalogTupleUpdate(), changeDependencyOnTablespace(), CheckRelationTableSpaceMove(), elog, ERROR, 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().