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

Go to the source code of this file.

Functions

ObjectAddress DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
 
TupleDesc BuildDescForRelation (const List *columns)
 
void RemoveRelations (DropStmt *drop)
 
Oid AlterTableLookupRelation (AlterTableStmt *stmt, LOCKMODE lockmode)
 
void AlterTable (AlterTableStmt *stmt, LOCKMODE lockmode, struct AlterTableUtilityContext *context)
 
LOCKMODE AlterTableGetLockLevel (List *cmds)
 
void ATExecChangeOwner (Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
 
void AlterTableInternal (Oid relid, List *cmds, bool recurse)
 
Oid AlterTableMoveAll (AlterTableMoveAllStmt *stmt)
 
ObjectAddress AlterTableNamespace (AlterObjectSchemaStmt *stmt, Oid *oldschema)
 
void AlterTableNamespaceInternal (Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
 
void AlterRelationNamespaceInternal (Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
 
void CheckTableNotInUse (Relation rel, const char *stmt)
 
void ExecuteTruncate (TruncateStmt *stmt)
 
void ExecuteTruncateGuts (List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs, 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)
 

Function Documentation

◆ AlterRelationNamespaceInternal()

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

Definition at line 18321 of file tablecmds.c.

18325{
18326 HeapTuple classTup;
18327 Form_pg_class classForm;
18328 ObjectAddress thisobj;
18329 bool already_done = false;
18330
18331 /* no rel lock for relkind=c so use LOCKTAG_TUPLE */
18332 classTup = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(relOid));
18333 if (!HeapTupleIsValid(classTup))
18334 elog(ERROR, "cache lookup failed for relation %u", relOid);
18335 classForm = (Form_pg_class) GETSTRUCT(classTup);
18336
18337 Assert(classForm->relnamespace == oldNspOid);
18338
18339 thisobj.classId = RelationRelationId;
18340 thisobj.objectId = relOid;
18341 thisobj.objectSubId = 0;
18342
18343 /*
18344 * If the object has already been moved, don't move it again. If it's
18345 * already in the right place, don't move it, but still fire the object
18346 * access hook.
18347 */
18348 already_done = object_address_present(&thisobj, objsMoved);
18349 if (!already_done && oldNspOid != newNspOid)
18350 {
18351 ItemPointerData otid = classTup->t_self;
18352
18353 /* check for duplicate name (more friendly than unique-index failure) */
18354 if (get_relname_relid(NameStr(classForm->relname),
18355 newNspOid) != InvalidOid)
18356 ereport(ERROR,
18357 (errcode(ERRCODE_DUPLICATE_TABLE),
18358 errmsg("relation \"%s\" already exists in schema \"%s\"",
18359 NameStr(classForm->relname),
18360 get_namespace_name(newNspOid))));
18361
18362 /* classTup is a copy, so OK to scribble on */
18363 classForm->relnamespace = newNspOid;
18364
18365 CatalogTupleUpdate(classRel, &otid, classTup);
18366 UnlockTuple(classRel, &otid, InplaceUpdateTupleLock);
18367
18368
18369 /* Update dependency on schema if caller said so */
18370 if (hasDependEntry &&
18371 changeDependencyFor(RelationRelationId,
18372 relOid,
18373 NamespaceRelationId,
18374 oldNspOid,
18375 newNspOid) != 1)
18376 elog(ERROR, "could not change schema dependency for relation \"%s\"",
18377 NameStr(classForm->relname));
18378 }
18379 else
18380 UnlockTuple(classRel, &classTup->t_self, InplaceUpdateTupleLock);
18381 if (!already_done)
18382 {
18383 add_exact_object_address(&thisobj, objsMoved);
18384
18385 InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
18386 }
18387
18388 heap_freetuple(classTup);
18389}
#define NameStr(name)
Definition: c.h:717
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2608
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2548
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
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, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
Definition: lmgr.c:601
#define InplaceUpdateTupleLock
Definition: lockdefs.h:48
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3449
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1968
#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:257
#define InvalidOid
Definition: postgres_ext.h:37
ItemPointerData t_self
Definition: htup.h:65
HeapTuple SearchSysCacheLockedCopy1(int cacheId, Datum key1)
Definition: syscache.c:404

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,
struct AlterTableUtilityContext context 
)

Definition at line 4495 of file tablecmds.c.

4497{
4498 Relation rel;
4499
4500 /* Caller is required to provide an adequate lock. */
4501 rel = relation_open(context->relid, NoLock);
4502
4504
4505 ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4506}
#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:4410
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4831

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

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4569 of file tablecmds.c.

4570{
4571 /*
4572 * This only works if we read catalog tables using MVCC snapshots.
4573 */
4574 ListCell *lcmd;
4576
4577 foreach(lcmd, cmds)
4578 {
4579 AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4580 LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4581
4582 switch (cmd->subtype)
4583 {
4584 /*
4585 * These subcommands rewrite the heap, so require full locks.
4586 */
4587 case AT_AddColumn: /* may rewrite heap, in some cases and visible
4588 * to SELECT */
4589 case AT_SetAccessMethod: /* must rewrite heap */
4590 case AT_SetTableSpace: /* must rewrite heap */
4591 case AT_AlterColumnType: /* must rewrite heap */
4592 cmd_lockmode = AccessExclusiveLock;
4593 break;
4594
4595 /*
4596 * These subcommands may require addition of toast tables. If
4597 * we add a toast table to a table currently being scanned, we
4598 * might miss data added to the new toast table by concurrent
4599 * insert transactions.
4600 */
4601 case AT_SetStorage: /* may add toast tables, see
4602 * ATRewriteCatalogs() */
4603 cmd_lockmode = AccessExclusiveLock;
4604 break;
4605
4606 /*
4607 * Removing constraints can affect SELECTs that have been
4608 * optimized assuming the constraint holds true. See also
4609 * CloneFkReferenced.
4610 */
4611 case AT_DropConstraint: /* as DROP INDEX */
4612 case AT_DropNotNull: /* may change some SQL plans */
4613 cmd_lockmode = AccessExclusiveLock;
4614 break;
4615
4616 /*
4617 * Subcommands that may be visible to concurrent SELECTs
4618 */
4619 case AT_DropColumn: /* change visible to SELECT */
4620 case AT_AddColumnToView: /* CREATE VIEW */
4621 case AT_DropOids: /* used to equiv to DropColumn */
4622 case AT_EnableAlwaysRule: /* may change SELECT rules */
4623 case AT_EnableReplicaRule: /* may change SELECT rules */
4624 case AT_EnableRule: /* may change SELECT rules */
4625 case AT_DisableRule: /* may change SELECT rules */
4626 cmd_lockmode = AccessExclusiveLock;
4627 break;
4628
4629 /*
4630 * Changing owner may remove implicit SELECT privileges
4631 */
4632 case AT_ChangeOwner: /* change visible to SELECT */
4633 cmd_lockmode = AccessExclusiveLock;
4634 break;
4635
4636 /*
4637 * Changing foreign table options may affect optimization.
4638 */
4639 case AT_GenericOptions:
4641 cmd_lockmode = AccessExclusiveLock;
4642 break;
4643
4644 /*
4645 * These subcommands affect write operations only.
4646 */
4647 case AT_EnableTrig:
4650 case AT_EnableTrigAll:
4651 case AT_EnableTrigUser:
4652 case AT_DisableTrig:
4653 case AT_DisableTrigAll:
4654 case AT_DisableTrigUser:
4655 cmd_lockmode = ShareRowExclusiveLock;
4656 break;
4657
4658 /*
4659 * These subcommands affect write operations only. XXX
4660 * Theoretically, these could be ShareRowExclusiveLock.
4661 */
4662 case AT_ColumnDefault:
4664 case AT_AlterConstraint:
4665 case AT_AddIndex: /* from ADD CONSTRAINT */
4667 case AT_ReplicaIdentity:
4668 case AT_SetNotNull:
4673 case AT_AddIdentity:
4674 case AT_DropIdentity:
4675 case AT_SetIdentity:
4676 case AT_SetExpression:
4677 case AT_DropExpression:
4678 case AT_SetCompression:
4679 cmd_lockmode = AccessExclusiveLock;
4680 break;
4681
4682 case AT_AddConstraint:
4683 case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4684 case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4685 if (IsA(cmd->def, Constraint))
4686 {
4687 Constraint *con = (Constraint *) cmd->def;
4688
4689 switch (con->contype)
4690 {
4691 case CONSTR_EXCLUSION:
4692 case CONSTR_PRIMARY:
4693 case CONSTR_UNIQUE:
4694
4695 /*
4696 * Cases essentially the same as CREATE INDEX. We
4697 * could reduce the lock strength to ShareLock if
4698 * we can work out how to allow concurrent catalog
4699 * updates. XXX Might be set down to
4700 * ShareRowExclusiveLock but requires further
4701 * analysis.
4702 */
4703 cmd_lockmode = AccessExclusiveLock;
4704 break;
4705 case CONSTR_FOREIGN:
4706
4707 /*
4708 * We add triggers to both tables when we add a
4709 * Foreign Key, so the lock level must be at least
4710 * as strong as CREATE TRIGGER.
4711 */
4712 cmd_lockmode = ShareRowExclusiveLock;
4713 break;
4714
4715 default:
4716 cmd_lockmode = AccessExclusiveLock;
4717 }
4718 }
4719 break;
4720
4721 /*
4722 * These subcommands affect inheritance behaviour. Queries
4723 * started before us will continue to see the old inheritance
4724 * behaviour, while queries started after we commit will see
4725 * new behaviour. No need to prevent reads or writes to the
4726 * subtable while we hook it up though. Changing the TupDesc
4727 * may be a problem, so keep highest lock.
4728 */
4729 case AT_AddInherit:
4730 case AT_DropInherit:
4731 cmd_lockmode = AccessExclusiveLock;
4732 break;
4733
4734 /*
4735 * These subcommands affect implicit row type conversion. They
4736 * have affects similar to CREATE/DROP CAST on queries. don't
4737 * provide for invalidating parse trees as a result of such
4738 * changes, so we keep these at AccessExclusiveLock.
4739 */
4740 case AT_AddOf:
4741 case AT_DropOf:
4742 cmd_lockmode = AccessExclusiveLock;
4743 break;
4744
4745 /*
4746 * Only used by CREATE OR REPLACE VIEW which must conflict
4747 * with an SELECTs currently using the view.
4748 */
4750 cmd_lockmode = AccessExclusiveLock;
4751 break;
4752
4753 /*
4754 * These subcommands affect general strategies for performance
4755 * and maintenance, though don't change the semantic results
4756 * from normal data reads and writes. Delaying an ALTER TABLE
4757 * behind currently active writes only delays the point where
4758 * the new strategy begins to take effect, so there is no
4759 * benefit in waiting. In this case the minimum restriction
4760 * applies: we don't currently allow concurrent catalog
4761 * updates.
4762 */
4763 case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4764 case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4765 case AT_DropCluster: /* Uses MVCC in getIndexes() */
4766 case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4767 case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4768 cmd_lockmode = ShareUpdateExclusiveLock;
4769 break;
4770
4771 case AT_SetLogged:
4772 case AT_SetUnLogged:
4773 cmd_lockmode = AccessExclusiveLock;
4774 break;
4775
4776 case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4777 cmd_lockmode = ShareUpdateExclusiveLock;
4778 break;
4779
4780 /*
4781 * Rel options are more complex than first appears. Options
4782 * are set here for tables, views and indexes; for historical
4783 * reasons these can all be used with ALTER TABLE, so we can't
4784 * decide between them using the basic grammar.
4785 */
4786 case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4787 * getTables() */
4788 case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4789 * getTables() */
4790 cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4791 break;
4792
4793 case AT_AttachPartition:
4794 cmd_lockmode = ShareUpdateExclusiveLock;
4795 break;
4796
4797 case AT_DetachPartition:
4798 if (((PartitionCmd *) cmd->def)->concurrent)
4799 cmd_lockmode = ShareUpdateExclusiveLock;
4800 else
4801 cmd_lockmode = AccessExclusiveLock;
4802 break;
4803
4805 cmd_lockmode = ShareUpdateExclusiveLock;
4806 break;
4807
4808 default: /* oops */
4809 elog(ERROR, "unrecognized alter table type: %d",
4810 (int) cmd->subtype);
4811 break;
4812 }
4813
4814 /*
4815 * Take the greatest lockmode from any subcommand
4816 */
4817 if (cmd_lockmode > lockmode)
4818 lockmode = cmd_lockmode;
4819 }
4820
4821 return lockmode;
4822}
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:160
@ CONSTR_FOREIGN
Definition: parsenodes.h:2791
@ CONSTR_UNIQUE
Definition: parsenodes.h:2789
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2790
@ CONSTR_PRIMARY
Definition: parsenodes.h:2788
@ AT_AddIndexConstraint
Definition: parsenodes.h:2425
@ AT_DropOf
Definition: parsenodes.h:2456
@ AT_SetOptions
Definition: parsenodes.h:2413
@ AT_DropIdentity
Definition: parsenodes.h:2468
@ AT_DisableTrigUser
Definition: parsenodes.h:2448
@ AT_DropNotNull
Definition: parsenodes.h:2408
@ AT_AddOf
Definition: parsenodes.h:2455
@ AT_ResetOptions
Definition: parsenodes.h:2414
@ AT_ReplicaIdentity
Definition: parsenodes.h:2457
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2440
@ AT_EnableRowSecurity
Definition: parsenodes.h:2458
@ AT_AddColumnToView
Definition: parsenodes.h:2405
@ AT_ResetRelOptions
Definition: parsenodes.h:2439
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2443
@ AT_DropOids
Definition: parsenodes.h:2435
@ AT_SetIdentity
Definition: parsenodes.h:2467
@ AT_SetUnLogged
Definition: parsenodes.h:2434
@ AT_DisableTrig
Definition: parsenodes.h:2444
@ AT_SetCompression
Definition: parsenodes.h:2416
@ AT_DropExpression
Definition: parsenodes.h:2411
@ AT_AddIndex
Definition: parsenodes.h:2418
@ AT_EnableReplicaRule
Definition: parsenodes.h:2451
@ AT_DropConstraint
Definition: parsenodes.h:2426
@ AT_SetNotNull
Definition: parsenodes.h:2409
@ AT_ClusterOn
Definition: parsenodes.h:2431
@ AT_AddIdentity
Definition: parsenodes.h:2466
@ AT_ForceRowSecurity
Definition: parsenodes.h:2460
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2450
@ AT_SetAccessMethod
Definition: parsenodes.h:2436
@ AT_AlterColumnType
Definition: parsenodes.h:2428
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2465
@ AT_AddInherit
Definition: parsenodes.h:2453
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2422
@ AT_EnableTrig
Definition: parsenodes.h:2441
@ AT_DropColumn
Definition: parsenodes.h:2417
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2429
@ AT_DisableTrigAll
Definition: parsenodes.h:2446
@ AT_EnableRule
Definition: parsenodes.h:2449
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2461
@ AT_DetachPartition
Definition: parsenodes.h:2464
@ AT_SetStatistics
Definition: parsenodes.h:2412
@ AT_AttachPartition
Definition: parsenodes.h:2463
@ AT_AddConstraint
Definition: parsenodes.h:2420
@ AT_DropInherit
Definition: parsenodes.h:2454
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2442
@ AT_SetLogged
Definition: parsenodes.h:2433
@ AT_SetStorage
Definition: parsenodes.h:2415
@ AT_DisableRule
Definition: parsenodes.h:2452
@ AT_DisableRowSecurity
Definition: parsenodes.h:2459
@ AT_SetRelOptions
Definition: parsenodes.h:2438
@ AT_ChangeOwner
Definition: parsenodes.h:2430
@ AT_EnableTrigUser
Definition: parsenodes.h:2447
@ AT_SetExpression
Definition: parsenodes.h:2410
@ AT_ReAddConstraint
Definition: parsenodes.h:2421
@ AT_SetTableSpace
Definition: parsenodes.h:2437
@ AT_GenericOptions
Definition: parsenodes.h:2462
@ AT_ColumnDefault
Definition: parsenodes.h:2406
@ AT_CookedColumnDefault
Definition: parsenodes.h:2407
@ AT_AlterConstraint
Definition: parsenodes.h:2423
@ AT_EnableTrigAll
Definition: parsenodes.h:2445
@ AT_DropCluster
Definition: parsenodes.h:2432
@ AT_ValidateConstraint
Definition: parsenodes.h:2424
@ AT_AddColumn
Definition: parsenodes.h:2404
#define lfirst(lc)
Definition: pg_list.h:172
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2143
AlterTableType subtype
Definition: parsenodes.h:2475
ConstrType contype
Definition: parsenodes.h:2815
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_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_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 4524 of file tablecmds.c.

4525{
4526 Relation rel;
4527 LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4528
4529 rel = relation_open(relid, lockmode);
4530
4532
4533 ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4534}
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4569

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4436 of file tablecmds.c.

4437{
4438 return RangeVarGetRelidExtended(stmt->relation, lockmode,
4439 stmt->missing_ok ? RVR_MISSING_OK : 0,
4441 stmt);
4442}
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:441
@ RVR_MISSING_OK
Definition: namespace.h:72
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:18853

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

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 16252 of file tablecmds.c.

16253{
16254 List *relations = NIL;
16255 ListCell *l;
16256 ScanKeyData key[1];
16257 Relation rel;
16258 TableScanDesc scan;
16259 HeapTuple tuple;
16260 Oid orig_tablespaceoid;
16261 Oid new_tablespaceoid;
16262 List *role_oids = roleSpecsToIds(stmt->roles);
16263
16264 /* Ensure we were not asked to move something we can't */
16265 if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
16266 stmt->objtype != OBJECT_MATVIEW)
16267 ereport(ERROR,
16268 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
16269 errmsg("only tables, indexes, and materialized views exist in tablespaces")));
16270
16271 /* Get the orig and new tablespace OIDs */
16272 orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
16273 new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
16274
16275 /* Can't move shared relations in to or out of pg_global */
16276 /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
16277 if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
16278 new_tablespaceoid == GLOBALTABLESPACE_OID)
16279 ereport(ERROR,
16280 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
16281 errmsg("cannot move relations in to or out of pg_global tablespace")));
16282
16283 /*
16284 * Must have CREATE rights on the new tablespace, unless it is the
16285 * database default tablespace (which all users implicitly have CREATE
16286 * rights on).
16287 */
16288 if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
16289 {
16290 AclResult aclresult;
16291
16292 aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
16293 ACL_CREATE);
16294 if (aclresult != ACLCHECK_OK)
16296 get_tablespace_name(new_tablespaceoid));
16297 }
16298
16299 /*
16300 * Now that the checks are done, check if we should set either to
16301 * InvalidOid because it is our database's default tablespace.
16302 */
16303 if (orig_tablespaceoid == MyDatabaseTableSpace)
16304 orig_tablespaceoid = InvalidOid;
16305
16306 if (new_tablespaceoid == MyDatabaseTableSpace)
16307 new_tablespaceoid = InvalidOid;
16308
16309 /* no-op */
16310 if (orig_tablespaceoid == new_tablespaceoid)
16311 return new_tablespaceoid;
16312
16313 /*
16314 * Walk the list of objects in the tablespace and move them. This will
16315 * only find objects in our database, of course.
16316 */
16317 ScanKeyInit(&key[0],
16318 Anum_pg_class_reltablespace,
16319 BTEqualStrategyNumber, F_OIDEQ,
16320 ObjectIdGetDatum(orig_tablespaceoid));
16321
16322 rel = table_open(RelationRelationId, AccessShareLock);
16323 scan = table_beginscan_catalog(rel, 1, key);
16324 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
16325 {
16326 Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
16327 Oid relOid = relForm->oid;
16328
16329 /*
16330 * Do not move objects in pg_catalog as part of this, if an admin
16331 * really wishes to do so, they can issue the individual ALTER
16332 * commands directly.
16333 *
16334 * Also, explicitly avoid any shared tables, temp tables, or TOAST
16335 * (TOAST will be moved with the main table).
16336 */
16337 if (IsCatalogNamespace(relForm->relnamespace) ||
16338 relForm->relisshared ||
16339 isAnyTempNamespace(relForm->relnamespace) ||
16340 IsToastNamespace(relForm->relnamespace))
16341 continue;
16342
16343 /* Only move the object type requested */
16344 if ((stmt->objtype == OBJECT_TABLE &&
16345 relForm->relkind != RELKIND_RELATION &&
16346 relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
16347 (stmt->objtype == OBJECT_INDEX &&
16348 relForm->relkind != RELKIND_INDEX &&
16349 relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
16350 (stmt->objtype == OBJECT_MATVIEW &&
16351 relForm->relkind != RELKIND_MATVIEW))
16352 continue;
16353
16354 /* Check if we are only moving objects owned by certain roles */
16355 if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
16356 continue;
16357
16358 /*
16359 * Handle permissions-checking here since we are locking the tables
16360 * and also to avoid doing a bunch of work only to fail part-way. Note
16361 * that permissions will also be checked by AlterTableInternal().
16362 *
16363 * Caller must be considered an owner on the table to move it.
16364 */
16365 if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
16367 NameStr(relForm->relname));
16368
16369 if (stmt->nowait &&
16371 ereport(ERROR,
16372 (errcode(ERRCODE_OBJECT_IN_USE),
16373 errmsg("aborting because lock on relation \"%s.%s\" is not available",
16374 get_namespace_name(relForm->relnamespace),
16375 NameStr(relForm->relname))));
16376 else
16378
16379 /* Add to our list of objects to move */
16380 relations = lappend_oid(relations, relOid);
16381 }
16382
16383 table_endscan(scan);
16385
16386 if (relations == NIL)
16388 (errcode(ERRCODE_NO_DATA_FOUND),
16389 errmsg("no matching relations in tablespace \"%s\" found",
16390 orig_tablespaceoid == InvalidOid ? "(database default)" :
16391 get_tablespace_name(orig_tablespaceoid))));
16392
16393 /* Everything is locked, loop through and move all of the relations. */
16394 foreach(l, relations)
16395 {
16396 List *cmds = NIL;
16398
16400 cmd->name = stmt->new_tablespacename;
16401
16402 cmds = lappend(cmds, cmd);
16403
16405 /* OID is set by AlterTableInternal */
16406 AlterTableInternal(lfirst_oid(l), cmds, false);
16408 }
16409
16410 return new_tablespaceoid;
16411}
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:2622
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3804
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4058
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:746
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:230
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:212
#define NOTICE
Definition: elog.h:35
void EventTriggerAlterTableStart(Node *parsetree)
void EventTriggerAlterTableEnd(void)
Oid MyDatabaseTableSpace
Definition: globals.c:95
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1347
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:2086
Oid GetUserId(void)
Definition: miscinit.c:520
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3687
#define makeNode(_type_)
Definition: nodes.h:157
ObjectType get_relkind_objtype(char relkind)
@ OBJECT_MATVIEW
Definition: parsenodes.h:2335
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2354
@ OBJECT_INDEX
Definition: parsenodes.h:2332
@ OBJECT_TABLE
Definition: parsenodes.h:2353
#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:131
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, struct ScanKeyData *key)
Definition: tableam.c:113
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:989
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4524
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 18213 of file tablecmds.c.

18214{
18215 Relation rel;
18216 Oid relid;
18217 Oid oldNspOid;
18218 Oid nspOid;
18219 RangeVar *newrv;
18220 ObjectAddresses *objsMoved;
18221 ObjectAddress myself;
18222
18224 stmt->missing_ok ? RVR_MISSING_OK : 0,
18226 stmt);
18227
18228 if (!OidIsValid(relid))
18229 {
18231 (errmsg("relation \"%s\" does not exist, skipping",
18232 stmt->relation->relname)));
18233 return InvalidObjectAddress;
18234 }
18235
18236 rel = relation_open(relid, NoLock);
18237
18238 oldNspOid = RelationGetNamespace(rel);
18239
18240 /* If it's an owned sequence, disallow moving it by itself. */
18241 if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
18242 {
18243 Oid tableId;
18244 int32 colId;
18245
18246 if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
18247 sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
18248 ereport(ERROR,
18249 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
18250 errmsg("cannot move an owned sequence into another schema"),
18251 errdetail("Sequence \"%s\" is linked to table \"%s\".",
18253 get_rel_name(tableId))));
18254 }
18255
18256 /* Get and lock schema OID and check its permissions. */
18257 newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
18258 nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
18259
18260 /* common checks on switching namespaces */
18261 CheckSetNamespace(oldNspOid, nspOid);
18262
18263 objsMoved = new_object_addresses();
18264 AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
18265 free_object_addresses(objsMoved);
18266
18267 ObjectAddressSet(myself, RelationRelationId, relid);
18268
18269 if (oldschema)
18270 *oldschema = oldNspOid;
18271
18272 /* close rel, but keep lock until commit */
18273 relation_close(rel, NoLock);
18274
18275 return myself;
18276}
int32_t int32
Definition: c.h:498
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2502
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2788
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int errdetail(const char *fmt,...)
Definition: elog.c:1203
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2011
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:739
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3459
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:547
#define RelationGetNamespace(relation)
Definition: rel.h:554
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:18284

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 18284 of file tablecmds.c.

18286{
18287 Relation classRel;
18288
18289 Assert(objsMoved != NULL);
18290
18291 /* OK, modify the pg_class row and pg_depend entry */
18292 classRel = table_open(RelationRelationId, RowExclusiveLock);
18293
18294 AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
18295 nspOid, true, objsMoved);
18296
18297 /* Fix the table's row type too, if it has one */
18298 if (OidIsValid(rel->rd_rel->reltype))
18299 AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid,
18300 false, /* isImplicitArray */
18301 false, /* ignoreDependent */
18302 false, /* errorOnTableType */
18303 objsMoved);
18304
18305 /* Fix other dependent stuff */
18306 AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
18307 AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
18308 objsMoved, AccessExclusiveLock);
18309 AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
18310 false, objsMoved);
18311
18312 table_close(classRel, RowExclusiveLock);
18313}
#define RowExclusiveLock
Definition: lockdefs.h:38
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
#define RelationGetRelid(relation)
Definition: rel.h:513
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:18321
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:18443
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:18398
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:4143

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 18726 of file tablecmds.c.

18728{
18729 ListCell *cur_item;
18730
18731 foreach(cur_item, on_commits)
18732 {
18733 OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
18734
18735 if (!isCommit && oc->creating_subid == mySubid)
18736 {
18737 /* cur_item must be removed */
18739 pfree(oc);
18740 }
18741 else
18742 {
18743 /* cur_item must be preserved */
18744 if (oc->creating_subid == mySubid)
18745 oc->creating_subid = parentSubid;
18746 if (oc->deleting_subid == mySubid)
18747 oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
18748 }
18749 }
18750}
#define InvalidSubTransactionId
Definition: c.h:629
void pfree(void *pointer)
Definition: mcxt.c:1524
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
SubTransactionId creating_subid
Definition: tablecmds.c:127
SubTransactionId deleting_subid
Definition: tablecmds.c:128
static List * on_commits
Definition: tablecmds.c:131

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 18694 of file tablecmds.c.

18695{
18696 ListCell *cur_item;
18697
18698 foreach(cur_item, on_commits)
18699 {
18700 OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
18701
18702 if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
18704 {
18705 /* cur_item must be removed */
18707 pfree(oc);
18708 }
18709 else
18710 {
18711 /* cur_item must be preserved */
18714 }
18715 }
18716}

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 15339 of file tablecmds.c.

15340{
15341 Relation target_rel;
15342 Relation class_rel;
15343 HeapTuple tuple;
15344 Form_pg_class tuple_class;
15345
15346 /*
15347 * Get exclusive lock till end of transaction on the target table. Use
15348 * relation_open so that we can work on indexes and sequences.
15349 */
15350 target_rel = relation_open(relationOid, lockmode);
15351
15352 /* Get its pg_class tuple, too */
15353 class_rel = table_open(RelationRelationId, RowExclusiveLock);
15354
15355 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
15356 if (!HeapTupleIsValid(tuple))
15357 elog(ERROR, "cache lookup failed for relation %u", relationOid);
15358 tuple_class = (Form_pg_class) GETSTRUCT(tuple);
15359
15360 /* Can we change the ownership of this tuple? */
15361 switch (tuple_class->relkind)
15362 {
15363 case RELKIND_RELATION:
15364 case RELKIND_VIEW:
15365 case RELKIND_MATVIEW:
15366 case RELKIND_FOREIGN_TABLE:
15367 case RELKIND_PARTITIONED_TABLE:
15368 /* ok to change owner */
15369 break;
15370 case RELKIND_INDEX:
15371 if (!recursing)
15372 {
15373 /*
15374 * Because ALTER INDEX OWNER used to be allowed, and in fact
15375 * is generated by old versions of pg_dump, we give a warning
15376 * and do nothing rather than erroring out. Also, to avoid
15377 * unnecessary chatter while restoring those old dumps, say
15378 * nothing at all if the command would be a no-op anyway.
15379 */
15380 if (tuple_class->relowner != newOwnerId)
15382 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15383 errmsg("cannot change owner of index \"%s\"",
15384 NameStr(tuple_class->relname)),
15385 errhint("Change the ownership of the index's table instead.")));
15386 /* quick hack to exit via the no-op path */
15387 newOwnerId = tuple_class->relowner;
15388 }
15389 break;
15390 case RELKIND_PARTITIONED_INDEX:
15391 if (recursing)
15392 break;
15393 ereport(ERROR,
15394 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15395 errmsg("cannot change owner of index \"%s\"",
15396 NameStr(tuple_class->relname)),
15397 errhint("Change the ownership of the index's table instead.")));
15398 break;
15399 case RELKIND_SEQUENCE:
15400 if (!recursing &&
15401 tuple_class->relowner != newOwnerId)
15402 {
15403 /* if it's an owned sequence, disallow changing it by itself */
15404 Oid tableId;
15405 int32 colId;
15406
15407 if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
15408 sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
15409 ereport(ERROR,
15410 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15411 errmsg("cannot change owner of sequence \"%s\"",
15412 NameStr(tuple_class->relname)),
15413 errdetail("Sequence \"%s\" is linked to table \"%s\".",
15414 NameStr(tuple_class->relname),
15415 get_rel_name(tableId))));
15416 }
15417 break;
15418 case RELKIND_COMPOSITE_TYPE:
15419 if (recursing)
15420 break;
15421 ereport(ERROR,
15422 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15423 errmsg("\"%s\" is a composite type",
15424 NameStr(tuple_class->relname)),
15425 /* translator: %s is an SQL ALTER command */
15426 errhint("Use %s instead.",
15427 "ALTER TYPE")));
15428 break;
15429 case RELKIND_TOASTVALUE:
15430 if (recursing)
15431 break;
15432 /* FALL THRU */
15433 default:
15434 ereport(ERROR,
15435 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15436 errmsg("cannot change owner of relation \"%s\"",
15437 NameStr(tuple_class->relname)),
15438 errdetail_relkind_not_supported(tuple_class->relkind)));
15439 }
15440
15441 /*
15442 * If the new owner is the same as the existing owner, consider the
15443 * command to have succeeded. This is for dump restoration purposes.
15444 */
15445 if (tuple_class->relowner != newOwnerId)
15446 {
15447 Datum repl_val[Natts_pg_class];
15448 bool repl_null[Natts_pg_class];
15449 bool repl_repl[Natts_pg_class];
15450 Acl *newAcl;
15451 Datum aclDatum;
15452 bool isNull;
15453 HeapTuple newtuple;
15454
15455 /* skip permission checks when recursing to index or toast table */
15456 if (!recursing)
15457 {
15458 /* Superusers can always do it */
15459 if (!superuser())
15460 {
15461 Oid namespaceOid = tuple_class->relnamespace;
15462 AclResult aclresult;
15463
15464 /* Otherwise, must be owner of the existing object */
15465 if (!object_ownercheck(RelationRelationId, relationOid, GetUserId()))
15467 RelationGetRelationName(target_rel));
15468
15469 /* Must be able to become new owner */
15470 check_can_set_role(GetUserId(), newOwnerId);
15471
15472 /* New owner must have CREATE privilege on namespace */
15473 aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId,
15474 ACL_CREATE);
15475 if (aclresult != ACLCHECK_OK)
15476 aclcheck_error(aclresult, OBJECT_SCHEMA,
15477 get_namespace_name(namespaceOid));
15478 }
15479 }
15480
15481 memset(repl_null, false, sizeof(repl_null));
15482 memset(repl_repl, false, sizeof(repl_repl));
15483
15484 repl_repl[Anum_pg_class_relowner - 1] = true;
15485 repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
15486
15487 /*
15488 * Determine the modified ACL for the new owner. This is only
15489 * necessary when the ACL is non-null.
15490 */
15491 aclDatum = SysCacheGetAttr(RELOID, tuple,
15492 Anum_pg_class_relacl,
15493 &isNull);
15494 if (!isNull)
15495 {
15496 newAcl = aclnewowner(DatumGetAclP(aclDatum),
15497 tuple_class->relowner, newOwnerId);
15498 repl_repl[Anum_pg_class_relacl - 1] = true;
15499 repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
15500 }
15501
15502 newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
15503
15504 CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
15505
15506 heap_freetuple(newtuple);
15507
15508 /*
15509 * We must similarly update any per-column ACLs to reflect the new
15510 * owner; for neatness reasons that's split out as a subroutine.
15511 */
15512 change_owner_fix_column_acls(relationOid,
15513 tuple_class->relowner,
15514 newOwnerId);
15515
15516 /*
15517 * Update owner dependency reference, if any. A composite type has
15518 * none, because it's tracked for the pg_type entry instead of here;
15519 * indexes and TOAST tables don't have their own entries either.
15520 */
15521 if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
15522 tuple_class->relkind != RELKIND_INDEX &&
15523 tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
15524 tuple_class->relkind != RELKIND_TOASTVALUE)
15525 changeDependencyOnOwner(RelationRelationId, relationOid,
15526 newOwnerId);
15527
15528 /*
15529 * Also change the ownership of the table's row type, if it has one
15530 */
15531 if (OidIsValid(tuple_class->reltype))
15532 AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
15533
15534 /*
15535 * If we are operating on a table or materialized view, also change
15536 * the ownership of any indexes and sequences that belong to the
15537 * relation, as well as its toast table (if it has one).
15538 */
15539 if (tuple_class->relkind == RELKIND_RELATION ||
15540 tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
15541 tuple_class->relkind == RELKIND_MATVIEW ||
15542 tuple_class->relkind == RELKIND_TOASTVALUE)
15543 {
15544 List *index_oid_list;
15545 ListCell *i;
15546
15547 /* Find all the indexes belonging to this relation */
15548 index_oid_list = RelationGetIndexList(target_rel);
15549
15550 /* For each index, recursively change its ownership */
15551 foreach(i, index_oid_list)
15552 ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
15553
15554 list_free(index_oid_list);
15555 }
15556
15557 /* If it has a toast table, recurse to change its ownership */
15558 if (tuple_class->reltoastrelid != InvalidOid)
15559 ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
15560 true, lockmode);
15561
15562 /* If it has dependent sequences, recurse to change them too */
15563 change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
15564 }
15565
15566 InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
15567
15568 ReleaseSysCache(tuple);
15569 table_close(class_rel, RowExclusiveLock);
15570 relation_close(target_rel, NoLock);
15571}
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1103
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5325
#define DatumGetAclP(X)
Definition: acl.h:120
int errhint(const char *fmt,...)
Definition: elog.c:1317
#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:74
void list_free(List *list)
Definition: list.c:1546
@ OBJECT_SCHEMA
Definition: parsenodes.h:2348
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:327
uintptr_t Datum
Definition: postgres.h:69
#define RelationGetDescr(relation)
Definition: rel.h:539
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4764
bool superuser(void)
Definition: superuser.c:46
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:15339
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:15645
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:15580
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3974

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 1341 of file tablecmds.c.

1342{
1343 int natts;
1345 ListCell *l;
1346 TupleDesc desc;
1347 char *attname;
1348 Oid atttypid;
1349 int32 atttypmod;
1350 Oid attcollation;
1351 int attdim;
1352
1353 /*
1354 * allocate a new tuple descriptor
1355 */
1356 natts = list_length(columns);
1357 desc = CreateTemplateTupleDesc(natts);
1358
1359 attnum = 0;
1360
1361 foreach(l, columns)
1362 {
1363 ColumnDef *entry = lfirst(l);
1364 AclResult aclresult;
1366
1367 /*
1368 * for each entry in the list, get the name and type information from
1369 * the list and have TupleDescInitEntry fill in the attribute
1370 * information we need.
1371 */
1372 attnum++;
1373
1374 attname = entry->colname;
1375 typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
1376
1377 aclresult = object_aclcheck(TypeRelationId, atttypid, GetUserId(), ACL_USAGE);
1378 if (aclresult != ACLCHECK_OK)
1379 aclcheck_error_type(aclresult, atttypid);
1380
1381 attcollation = GetColumnDefCollation(NULL, entry, atttypid);
1382 attdim = list_length(entry->typeName->arrayBounds);
1383 if (attdim > PG_INT16_MAX)
1384 ereport(ERROR,
1385 errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1386 errmsg("too many array dimensions"));
1387
1388 if (entry->typeName->setof)
1389 ereport(ERROR,
1390 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
1391 errmsg("column \"%s\" cannot be declared SETOF",
1392 attname)));
1393
1395 atttypid, atttypmod, attdim);
1396 att = TupleDescAttr(desc, attnum - 1);
1397
1398 /* Override TupleDescInitEntry's settings as requested */
1399 TupleDescInitEntryCollation(desc, attnum, attcollation);
1400
1401 /* Fill in additional stuff not handled by TupleDescInitEntry */
1402 att->attnotnull = entry->is_not_null;
1403 att->attislocal = entry->is_local;
1404 att->attinhcount = entry->inhcount;
1405 att->attidentity = entry->identity;
1406 att->attgenerated = entry->generated;
1407 att->attcompression = GetAttributeCompression(att->atttypid, entry->compression);
1408 if (entry->storage)
1409 att->attstorage = entry->storage;
1410 else if (entry->storage_name)
1411 att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name);
1412
1414 }
1415
1416 return desc;
1417}
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:2941
int16 AttrNumber
Definition: attnum.h:21
#define PG_INT16_MAX
Definition: c.h:557
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:200
static int list_length(const List *l)
Definition: pg_list.h:152
bool is_not_null
Definition: parsenodes.h:742
char identity
Definition: parsenodes.h:748
char * storage_name
Definition: parsenodes.h:745
char * colname
Definition: parsenodes.h:737
TypeName * typeName
Definition: parsenodes.h:738
char generated
Definition: parsenodes.h:751
char storage
Definition: parsenodes.h:744
bool is_local
Definition: parsenodes.h:741
int16 inhcount
Definition: parsenodes.h:740
char * compression
Definition: parsenodes.h:739
bool setof
Definition: parsenodes.h:281
List * arrayBounds
Definition: parsenodes.h:285
static char GetAttributeCompression(Oid atttypid, const char *compression)
Definition: tablecmds.c:21280
static char GetAttributeStorage(Oid atttypid, const char *storagemode)
Definition: tablecmds.c:21318
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:164
void populate_compact_attribute(TupleDesc tupdesc, int attnum)
Definition: tupdesc.c:107
void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid)
Definition: tupdesc.c:985
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:801
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:154

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(), DefineRelation(), and DefineVirtualRelation().

◆ check_of_type()

void check_of_type ( HeapTuple  typetuple)

Definition at line 7046 of file tablecmds.c.

7047{
7048 Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
7049 bool typeOk = false;
7050
7051 if (typ->typtype == TYPTYPE_COMPOSITE)
7052 {
7053 Relation typeRelation;
7054
7055 Assert(OidIsValid(typ->typrelid));
7056 typeRelation = relation_open(typ->typrelid, AccessShareLock);
7057 typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
7058
7059 /*
7060 * Close the parent rel, but keep our AccessShareLock on it until xact
7061 * commit. That will prevent someone else from deleting or ALTERing
7062 * the type before the typed table creation/conversion commits.
7063 */
7064 relation_close(typeRelation, NoLock);
7065
7066 if (!typeOk)
7067 ereport(ERROR,
7068 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7069 errmsg("type %s is the row type of another table",
7070 format_type_be(typ->oid)),
7071 errdetail("A typed table must use a stand-alone composite type created with CREATE TYPE.")));
7072 }
7073 else
7074 ereport(ERROR,
7075 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7076 errmsg("type %s is not a composite type",
7077 format_type_be(typ->oid))));
7078}
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 3654 of file tablecmds.c.

3655{
3656 Oid oldTableSpaceId;
3657
3658 /*
3659 * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3660 * stored as 0.
3661 */
3662 oldTableSpaceId = rel->rd_rel->reltablespace;
3663 if (newTableSpaceId == oldTableSpaceId ||
3664 (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3665 return false;
3666
3667 /*
3668 * We cannot support moving mapped relations into different tablespaces.
3669 * (In particular this eliminates all shared catalogs.)
3670 */
3671 if (RelationIsMapped(rel))
3672 ereport(ERROR,
3673 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3674 errmsg("cannot move system relation \"%s\"",
3676
3677 /* Cannot move a non-shared relation into pg_global */
3678 if (newTableSpaceId == GLOBALTABLESPACE_OID)
3679 ereport(ERROR,
3680 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3681 errmsg("only shared relations can be placed in pg_global tablespace")));
3682
3683 /*
3684 * Do not allow moving temp tables of other backends ... their local
3685 * buffer manager is not going to cope.
3686 */
3687 if (RELATION_IS_OTHER_TEMP(rel))
3688 ereport(ERROR,
3689 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3690 errmsg("cannot move temporary tables of other sessions")));
3691
3692 return true;
3693}
#define RelationIsMapped(relation)
Definition: rel.h:562
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:666

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 4377 of file tablecmds.c.

4378{
4379 int expected_refcnt;
4380
4381 expected_refcnt = rel->rd_isnailed ? 2 : 1;
4382 if (rel->rd_refcnt != expected_refcnt)
4383 ereport(ERROR,
4384 (errcode(ERRCODE_OBJECT_IN_USE),
4385 /* translator: first %s is a SQL command, eg ALTER TABLE */
4386 errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
4388
4389 if (rel->rd_rel->relkind != RELKIND_INDEX &&
4390 rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
4392 ereport(ERROR,
4393 (errcode(ERRCODE_OBJECT_IN_USE),
4394 /* translator: first %s is a SQL command, eg ALTER TABLE */
4395 errmsg("cannot %s \"%s\" because it has pending trigger events",
4397}
int rd_refcnt
Definition: rel.h:59
bool rd_isnailed
Definition: rel.h:62
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:6024

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 735 of file tablecmds.c.

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

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(), 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 1822 of file tablecmds.c.

1823{
1824 List *rels = NIL;
1825 List *relids = NIL;
1826 List *relids_logged = NIL;
1827 ListCell *cell;
1828
1829 /*
1830 * Open, exclusive-lock, and check all the explicitly-specified relations
1831 */
1832 foreach(cell, stmt->relations)
1833 {
1834 RangeVar *rv = lfirst(cell);
1835 Relation rel;
1836 bool recurse = rv->inh;
1837 Oid myrelid;
1838 LOCKMODE lockmode = AccessExclusiveLock;
1839
1840 myrelid = RangeVarGetRelidExtended(rv, lockmode,
1842 NULL);
1843
1844 /* don't throw error for "TRUNCATE foo, foo" */
1845 if (list_member_oid(relids, myrelid))
1846 continue;
1847
1848 /* open the relation, we already hold a lock on it */
1849 rel = table_open(myrelid, NoLock);
1850
1851 /*
1852 * RangeVarGetRelidExtended() has done most checks with its callback,
1853 * but other checks with the now-opened Relation remain.
1854 */
1856
1857 rels = lappend(rels, rel);
1858 relids = lappend_oid(relids, myrelid);
1859
1860 /* Log this relation only if needed for logical decoding */
1862 relids_logged = lappend_oid(relids_logged, myrelid);
1863
1864 if (recurse)
1865 {
1866 ListCell *child;
1867 List *children;
1868
1869 children = find_all_inheritors(myrelid, lockmode, NULL);
1870
1871 foreach(child, children)
1872 {
1873 Oid childrelid = lfirst_oid(child);
1874
1875 if (list_member_oid(relids, childrelid))
1876 continue;
1877
1878 /* find_all_inheritors already got lock */
1879 rel = table_open(childrelid, NoLock);
1880
1881 /*
1882 * It is possible that the parent table has children that are
1883 * temp tables of other backends. We cannot safely access
1884 * such tables (because of buffering issues), and the best
1885 * thing to do is to silently ignore them. Note that this
1886 * check is the same as one of the checks done in
1887 * truncate_check_activity() called below, still it is kept
1888 * here for simplicity.
1889 */
1890 if (RELATION_IS_OTHER_TEMP(rel))
1891 {
1892 table_close(rel, lockmode);
1893 continue;
1894 }
1895
1896 /*
1897 * Inherited TRUNCATE commands perform access permission
1898 * checks on the parent table only. So we skip checking the
1899 * children's permissions and don't call
1900 * truncate_check_perms() here.
1901 */
1904
1905 rels = lappend(rels, rel);
1906 relids = lappend_oid(relids, childrelid);
1907
1908 /* Log this relation only if needed for logical decoding */
1910 relids_logged = lappend_oid(relids_logged, childrelid);
1911 }
1912 }
1913 else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1914 ereport(ERROR,
1915 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1916 errmsg("cannot truncate only a partitioned table"),
1917 errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1918 }
1919
1920 ExecuteTruncateGuts(rels, relids, relids_logged,
1921 stmt->behavior, stmt->restart_seqs, false);
1922
1923 /* And close the rels */
1924 foreach(cell, rels)
1925 {
1926 Relation rel = (Relation) lfirst(cell);
1927
1928 table_close(rel, NoLock);
1929 }
1930}
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:709
struct RelationData * Relation
Definition: relcache.h:27
bool inh
Definition: primnodes.h:86
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2399
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2333
static void RangeVarCallbackForTruncate(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:18797
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs, bool run_as_table_owner)
Definition: tablecmds.c:1946

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 1946 of file tablecmds.c.

1951{
1952 List *rels;
1953 List *seq_relids = NIL;
1954 HTAB *ft_htab = NULL;
1955 EState *estate;
1956 ResultRelInfo *resultRelInfos;
1957 ResultRelInfo *resultRelInfo;
1958 SubTransactionId mySubid;
1959 ListCell *cell;
1960 Oid *logrelids;
1961
1962 /*
1963 * Check the explicitly-specified relations.
1964 *
1965 * In CASCADE mode, suck in all referencing relations as well. This
1966 * requires multiple iterations to find indirectly-dependent relations. At
1967 * each phase, we need to exclusive-lock new rels before looking for their
1968 * dependencies, else we might miss something. Also, we check each rel as
1969 * soon as we open it, to avoid a faux pas such as holding lock for a long
1970 * time on a rel we have no permissions for.
1971 */
1972 rels = list_copy(explicit_rels);
1973 if (behavior == DROP_CASCADE)
1974 {
1975 for (;;)
1976 {
1977 List *newrelids;
1978
1979 newrelids = heap_truncate_find_FKs(relids);
1980 if (newrelids == NIL)
1981 break; /* nothing else to add */
1982
1983 foreach(cell, newrelids)
1984 {
1985 Oid relid = lfirst_oid(cell);
1986 Relation rel;
1987
1988 rel = table_open(relid, AccessExclusiveLock);
1990 (errmsg("truncate cascades to table \"%s\"",
1992 truncate_check_rel(relid, rel->rd_rel);
1993 truncate_check_perms(relid, rel->rd_rel);
1995 rels = lappend(rels, rel);
1996 relids = lappend_oid(relids, relid);
1997
1998 /* Log this relation only if needed for logical decoding */
2000 relids_logged = lappend_oid(relids_logged, relid);
2001 }
2002 }
2003 }
2004
2005 /*
2006 * Check foreign key references. In CASCADE mode, this should be
2007 * unnecessary since we just pulled in all the references; but as a
2008 * cross-check, do it anyway if in an Assert-enabled build.
2009 */
2010#ifdef USE_ASSERT_CHECKING
2011 heap_truncate_check_FKs(rels, false);
2012#else
2013 if (behavior == DROP_RESTRICT)
2014 heap_truncate_check_FKs(rels, false);
2015#endif
2016
2017 /*
2018 * If we are asked to restart sequences, find all the sequences, lock them
2019 * (we need AccessExclusiveLock for ResetSequence), and check permissions.
2020 * We want to do this early since it's pointless to do all the truncation
2021 * work only to fail on sequence permissions.
2022 */
2023 if (restart_seqs)
2024 {
2025 foreach(cell, rels)
2026 {
2027 Relation rel = (Relation) lfirst(cell);
2028 List *seqlist = getOwnedSequences(RelationGetRelid(rel));
2029 ListCell *seqcell;
2030
2031 foreach(seqcell, seqlist)
2032 {
2033 Oid seq_relid = lfirst_oid(seqcell);
2034 Relation seq_rel;
2035
2036 seq_rel = relation_open(seq_relid, AccessExclusiveLock);
2037
2038 /* This check must match AlterSequence! */
2039 if (!object_ownercheck(RelationRelationId, seq_relid, GetUserId()))
2041 RelationGetRelationName(seq_rel));
2042
2043 seq_relids = lappend_oid(seq_relids, seq_relid);
2044
2045 relation_close(seq_rel, NoLock);
2046 }
2047 }
2048 }
2049
2050 /* Prepare to catch AFTER triggers. */
2052
2053 /*
2054 * To fire triggers, we'll need an EState as well as a ResultRelInfo for
2055 * each relation. We don't need to call ExecOpenIndices, though.
2056 *
2057 * We put the ResultRelInfos in the es_opened_result_relations list, even
2058 * though we don't have a range table and don't populate the
2059 * es_result_relations array. That's a bit bogus, but it's enough to make
2060 * ExecGetTriggerResultRel() find them.
2061 */
2062 estate = CreateExecutorState();
2063 resultRelInfos = (ResultRelInfo *)
2064 palloc(list_length(rels) * sizeof(ResultRelInfo));
2065 resultRelInfo = resultRelInfos;
2066 foreach(cell, rels)
2067 {
2068 Relation rel = (Relation) lfirst(cell);
2069
2070 InitResultRelInfo(resultRelInfo,
2071 rel,
2072 0, /* dummy rangetable index */
2073 NULL,
2074 0);
2076 lappend(estate->es_opened_result_relations, resultRelInfo);
2077 resultRelInfo++;
2078 }
2079
2080 /*
2081 * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
2082 * truncating (this is because one of them might throw an error). Also, if
2083 * we were to allow them to prevent statement execution, that would need
2084 * to be handled here.
2085 */
2086 resultRelInfo = resultRelInfos;
2087 foreach(cell, rels)
2088 {
2089 UserContext ucxt;
2090
2091 if (run_as_table_owner)
2092 SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2093 &ucxt);
2094 ExecBSTruncateTriggers(estate, resultRelInfo);
2095 if (run_as_table_owner)
2096 RestoreUserContext(&ucxt);
2097 resultRelInfo++;
2098 }
2099
2100 /*
2101 * OK, truncate each table.
2102 */
2103 mySubid = GetCurrentSubTransactionId();
2104
2105 foreach(cell, rels)
2106 {
2107 Relation rel = (Relation) lfirst(cell);
2108
2109 /* Skip partitioned tables as there is nothing to do */
2110 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
2111 continue;
2112
2113 /*
2114 * Build the lists of foreign tables belonging to each foreign server
2115 * and pass each list to the foreign data wrapper's callback function,
2116 * so that each server can truncate its all foreign tables in bulk.
2117 * Each list is saved as a single entry in a hash table that uses the
2118 * server OID as lookup key.
2119 */
2120 if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2121 {
2123 bool found;
2124 ForeignTruncateInfo *ft_info;
2125
2126 /* First time through, initialize hashtable for foreign tables */
2127 if (!ft_htab)
2128 {
2129 HASHCTL hctl;
2130
2131 memset(&hctl, 0, sizeof(HASHCTL));
2132 hctl.keysize = sizeof(Oid);
2133 hctl.entrysize = sizeof(ForeignTruncateInfo);
2135
2136 ft_htab = hash_create("TRUNCATE for Foreign Tables",
2137 32, /* start small and extend */
2138 &hctl,
2140 }
2141
2142 /* Find or create cached entry for the foreign table */
2143 ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
2144 if (!found)
2145 ft_info->rels = NIL;
2146
2147 /*
2148 * Save the foreign table in the entry of the server that the
2149 * foreign table belongs to.
2150 */
2151 ft_info->rels = lappend(ft_info->rels, rel);
2152 continue;
2153 }
2154
2155 /*
2156 * Normally, we need a transaction-safe truncation here. However, if
2157 * the table was either created in the current (sub)transaction or has
2158 * a new relfilenumber in the current (sub)transaction, then we can
2159 * just truncate it in-place, because a rollback would cause the whole
2160 * table or the current physical file to be thrown away anyway.
2161 */
2162 if (rel->rd_createSubid == mySubid ||
2163 rel->rd_newRelfilelocatorSubid == mySubid)
2164 {
2165 /* Immediate, non-rollbackable truncation is OK */
2167 }
2168 else
2169 {
2170 Oid heap_relid;
2171 Oid toast_relid;
2172 ReindexParams reindex_params = {0};
2173
2174 /*
2175 * This effectively deletes all rows in the table, and may be done
2176 * in a serializable transaction. In that case we must record a
2177 * rw-conflict in to this transaction from each transaction
2178 * holding a predicate lock on the table.
2179 */
2181
2182 /*
2183 * Need the full transaction-safe pushups.
2184 *
2185 * Create a new empty storage file for the relation, and assign it
2186 * as the relfilenumber value. The old storage file is scheduled
2187 * for deletion at commit.
2188 */
2189 RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);
2190
2191 heap_relid = RelationGetRelid(rel);
2192
2193 /*
2194 * The same for the toast table, if any.
2195 */
2196 toast_relid = rel->rd_rel->reltoastrelid;
2197 if (OidIsValid(toast_relid))
2198 {
2199 Relation toastrel = relation_open(toast_relid,
2201
2203 toastrel->rd_rel->relpersistence);
2204 table_close(toastrel, NoLock);
2205 }
2206
2207 /*
2208 * Reconstruct the indexes to match, and we're done.
2209 */
2211 &reindex_params);
2212 }
2213
2215 }
2216
2217 /* Now go through the hash table, and truncate foreign tables */
2218 if (ft_htab)
2219 {
2220 ForeignTruncateInfo *ft_info;
2221 HASH_SEQ_STATUS seq;
2222
2223 hash_seq_init(&seq, ft_htab);
2224
2225 PG_TRY();
2226 {
2227 while ((ft_info = hash_seq_search(&seq)) != NULL)
2228 {
2229 FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2230
2231 /* truncate_check_rel() has checked that already */
2232 Assert(routine->ExecForeignTruncate != NULL);
2233
2234 routine->ExecForeignTruncate(ft_info->rels,
2235 behavior,
2236 restart_seqs);
2237 }
2238 }
2239 PG_FINALLY();
2240 {
2241 hash_destroy(ft_htab);
2242 }
2243 PG_END_TRY();
2244 }
2245
2246 /*
2247 * Restart owned sequences if we were asked to.
2248 */
2249 foreach(cell, seq_relids)
2250 {
2251 Oid seq_relid = lfirst_oid(cell);
2252
2253 ResetSequence(seq_relid);
2254 }
2255
2256 /*
2257 * Write a WAL record to allow this set of actions to be logically
2258 * decoded.
2259 *
2260 * Assemble an array of relids so we can write a single WAL record for the
2261 * whole action.
2262 */
2263 if (relids_logged != NIL)
2264 {
2265 xl_heap_truncate xlrec;
2266 int i = 0;
2267
2268 /* should only get here if wal_level >= logical */
2270
2271 logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
2272 foreach(cell, relids_logged)
2273 logrelids[i++] = lfirst_oid(cell);
2274
2275 xlrec.dbId = MyDatabaseId;
2276 xlrec.nrelids = list_length(relids_logged);
2277 xlrec.flags = 0;
2278 if (behavior == DROP_CASCADE)
2279 xlrec.flags |= XLH_TRUNCATE_CASCADE;
2280 if (restart_seqs)
2282
2285 XLogRegisterData(logrelids, list_length(relids_logged) * sizeof(Oid));
2286
2288
2289 (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
2290 }
2291
2292 /*
2293 * Process all AFTER STATEMENT TRUNCATE triggers.
2294 */
2295 resultRelInfo = resultRelInfos;
2296 foreach(cell, rels)
2297 {
2298 UserContext ucxt;
2299
2300 if (run_as_table_owner)
2301 SwitchToUntrustedUser(resultRelInfo->ri_RelationDesc->rd_rel->relowner,
2302 &ucxt);
2303 ExecASTruncateTriggers(estate, resultRelInfo);
2304 if (run_as_table_owner)
2305 RestoreUserContext(&ucxt);
2306 resultRelInfo++;
2307 }
2308
2309 /* Handle queued AFTER triggers */
2310 AfterTriggerEndQuery(estate);
2311
2312 /* We can clean up the EState now */
2313 FreeExecutorState(estate);
2314
2315 /*
2316 * Close any rels opened by CASCADE (can't do this while EState still
2317 * holds refs)
2318 */
2319 rels = list_difference_ptr(rels, explicit_rels);
2320 foreach(cell, rels)
2321 {
2322 Relation rel = (Relation) lfirst(cell);
2323
2324 table_close(rel, NoLock);
2325 }
2326}
uint32 SubTransactionId
Definition: c.h:627
void ResetSequence(Oid seq_relid)
Definition: sequence.c:262
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1420
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define PG_FINALLY(...)
Definition: elog.h:388
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition: execMain.c:1326
void FreeExecutorState(EState *estate)
Definition: execUtils.c:193
EState * CreateExecutorState(void)
Definition: execUtils.c:88
struct ResultRelInfo ResultRelInfo
FdwRoutine * GetFdwRoutineByServerId(Oid serverid)
Definition: foreign.c:377
Oid GetForeignServerIdByRelId(Oid relid)
Definition: foreign.c:355
Oid MyDatabaseId
Definition: globals.c:93
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3678
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3583
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3539
#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:3948
#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
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
@ DROP_CASCADE
Definition: parsenodes.h:2386
@ DROP_RESTRICT
Definition: parsenodes.h:2385
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2349
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:936
void pgstat_count_truncate(Relation rel)
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4409
void RelationSetNewRelfilenumber(Relation relation, char persistence)
Definition: relcache.c:3725
List * es_opened_result_relations
Definition: execnodes.h:680
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:220
SubTransactionId rd_newRelfilelocatorSubid
Definition: rel.h:104
SubTransactionId rd_createSubid
Definition: rel.h:103
Relation ri_RelationDesc
Definition: execnodes.h:475
struct ForeignTruncateInfo ForeignTruncateInfo
static void truncate_check_perms(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2381
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3231
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3278
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:5088
void AfterTriggerBeginQuery(void)
Definition: trigger.c:5053
void SwitchToUntrustedUser(Oid userid, UserContext *context)
Definition: usercontext.c:33
void RestoreUserContext(UserContext *context)
Definition: usercontext.c:87
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:791
#define XLogLogicalInfoActive()
Definition: xlog.h:126
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:154
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogRegisterData(const void *data, uint32 len)
Definition: xloginsert.c:364
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:456
void XLogBeginInsert(void)
Definition: xloginsert.c:149

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 6839 of file tablecmds.c.

6841{
6842 Relation depRel;
6843 ScanKeyData key[2];
6844 SysScanDesc depScan;
6845 HeapTuple depTup;
6846
6847 /* since this function recurses, it could be driven to stack overflow */
6849
6850 /*
6851 * We scan pg_depend to find those things that depend on the given type.
6852 * (We assume we can ignore refobjsubid for a type.)
6853 */
6854 depRel = table_open(DependRelationId, AccessShareLock);
6855
6856 ScanKeyInit(&key[0],
6857 Anum_pg_depend_refclassid,
6858 BTEqualStrategyNumber, F_OIDEQ,
6859 ObjectIdGetDatum(TypeRelationId));
6860 ScanKeyInit(&key[1],
6861 Anum_pg_depend_refobjid,
6862 BTEqualStrategyNumber, F_OIDEQ,
6863 ObjectIdGetDatum(typeOid));
6864
6865 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6866 NULL, 2, key);
6867
6868 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6869 {
6870 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6871 Relation rel;
6872 TupleDesc tupleDesc;
6874
6875 /* Check for directly dependent types */
6876 if (pg_depend->classid == TypeRelationId)
6877 {
6878 /*
6879 * This must be an array, domain, or range containing the given
6880 * type, so recursively check for uses of this type. Note that
6881 * any error message will mention the original type not the
6882 * container; this is intentional.
6883 */
6884 find_composite_type_dependencies(pg_depend->objid,
6885 origRelation, origTypeName);
6886 continue;
6887 }
6888
6889 /* Else, ignore dependees that aren't relations */
6890 if (pg_depend->classid != RelationRelationId)
6891 continue;
6892
6893 rel = relation_open(pg_depend->objid, AccessShareLock);
6894 tupleDesc = RelationGetDescr(rel);
6895
6896 /*
6897 * If objsubid identifies a specific column, refer to that in error
6898 * messages. Otherwise, search to see if there's a user column of the
6899 * type. (We assume system columns are never of interesting types.)
6900 * The search is needed because an index containing an expression
6901 * column of the target type will just be recorded as a whole-relation
6902 * dependency. If we do not find a column of the type, the dependency
6903 * must indicate that the type is transiently referenced in an index
6904 * expression but not stored on disk, which we assume is OK, just as
6905 * we do for references in views. (It could also be that the target
6906 * type is embedded in some container type that is stored in an index
6907 * column, but the previous recursion should catch such cases.)
6908 */
6909 if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
6910 att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
6911 else
6912 {
6913 att = NULL;
6914 for (int attno = 1; attno <= tupleDesc->natts; attno++)
6915 {
6916 att = TupleDescAttr(tupleDesc, attno - 1);
6917 if (att->atttypid == typeOid && !att->attisdropped)
6918 break;
6919 att = NULL;
6920 }
6921 if (att == NULL)
6922 {
6923 /* No such column, so assume OK */
6925 continue;
6926 }
6927 }
6928
6929 /*
6930 * We definitely should reject if the relation has storage. If it's
6931 * partitioned, then perhaps we don't have to reject: if there are
6932 * partitions then we'll fail when we find one, else there is no
6933 * stored data to worry about. However, it's possible that the type
6934 * change would affect conclusions about whether the type is sortable
6935 * or hashable and thus (if it's a partitioning column) break the
6936 * partitioning rule. For now, reject for partitioned rels too.
6937 */
6938 if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
6939 RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
6940 {
6941 if (origTypeName)
6942 ereport(ERROR,
6943 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6944 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6945 origTypeName,
6947 NameStr(att->attname))));
6948 else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6949 ereport(ERROR,
6950 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6951 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6952 RelationGetRelationName(origRelation),
6954 NameStr(att->attname))));
6955 else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
6956 ereport(ERROR,
6957 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6958 errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
6959 RelationGetRelationName(origRelation),
6961 NameStr(att->attname))));
6962 else
6963 ereport(ERROR,
6964 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6965 errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
6966 RelationGetRelationName(origRelation),
6968 NameStr(att->attname))));
6969 }
6970 else if (OidIsValid(rel->rd_rel->reltype))
6971 {
6972 /*
6973 * A view or composite type itself isn't a problem, but we must
6974 * recursively check for indirect dependencies via its rowtype.
6975 */
6977 origRelation, origTypeName);
6978 }
6979
6981 }
6982
6983 systable_endscan(depScan);
6984
6986}
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:6839

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 19316 of file tablecmds.c.

19318{
19319 List *existConstraint = NIL;
19320 TupleConstr *constr = RelationGetDescr(scanrel)->constr;
19321 int i;
19322
19323 if (constr && constr->has_not_null)
19324 {
19325 int natts = scanrel->rd_att->natts;
19326
19327 for (i = 1; i <= natts; i++)
19328 {
19329 Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
19330
19331 if (att->attnotnull && !att->attisdropped)
19332 {
19333 NullTest *ntest = makeNode(NullTest);
19334
19335 ntest->arg = (Expr *) makeVar(1,
19336 i,
19337 att->atttypid,
19338 att->atttypmod,
19339 att->attcollation,
19340 0);
19341 ntest->nulltesttype = IS_NOT_NULL;
19342
19343 /*
19344 * argisrow=false is correct even for a composite column,
19345 * because attnotnull does not represent a SQL-spec IS NOT
19346 * NULL test in such a case, just IS DISTINCT FROM NULL.
19347 */
19348 ntest->argisrow = false;
19349 ntest->location = -1;
19350 existConstraint = lappend(existConstraint, ntest);
19351 }
19352 }
19353 }
19354
19355 return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
19356}
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
@ IS_NOT_NULL
Definition: primnodes.h:1957
NullTestType nulltesttype
Definition: primnodes.h:1964
ParseLoc location
Definition: primnodes.h:1967
Expr * arg
Definition: primnodes.h:1963
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:19369

References NullTest::arg, ConstraintImpliedByRelConstraint(), TupleConstr::has_not_null, i, IS_NOT_NULL, lappend(), NullTest::location, makeNode, makeVar(), TupleDescData::natts, NIL, NullTest::nulltesttype, RelationData::rd_att, RelationGetDescr, and TupleDescAttr().

Referenced by check_default_partition_contents(), DetachAddConstraintIfNeeded(), and QueuePartitionConstraintValidation().

◆ PreCommit_on_commit_actions()

void PreCommit_on_commit_actions ( void  )

Definition at line 18587 of file tablecmds.c.

18588{
18589 ListCell *l;
18590 List *oids_to_truncate = NIL;
18591 List *oids_to_drop = NIL;
18592
18593 foreach(l, on_commits)
18594 {
18595 OnCommitItem *oc = (OnCommitItem *) lfirst(l);
18596
18597 /* Ignore entry if already dropped in this xact */
18599 continue;
18600
18601 switch (oc->oncommit)
18602 {
18603 case ONCOMMIT_NOOP:
18605 /* Do nothing (there shouldn't be such entries, actually) */
18606 break;
18608
18609 /*
18610 * If this transaction hasn't accessed any temporary
18611 * relations, we can skip truncating ON COMMIT DELETE ROWS
18612 * tables, as they must still be empty.
18613 */
18615 oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
18616 break;
18617 case ONCOMMIT_DROP:
18618 oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
18619 break;
18620 }
18621 }
18622
18623 /*
18624 * Truncate relations before dropping so that all dependencies between
18625 * relations are removed after they are worked on. Doing it like this
18626 * might be a waste as it is possible that a relation being truncated will
18627 * be dropped anyway due to its parent being dropped, but this makes the
18628 * code more robust because of not having to re-check that the relation
18629 * exists at truncation time.
18630 */
18631 if (oids_to_truncate != NIL)
18632 heap_truncate(oids_to_truncate);
18633
18634 if (oids_to_drop != NIL)
18635 {
18636 ObjectAddresses *targetObjects = new_object_addresses();
18637
18638 foreach(l, oids_to_drop)
18639 {
18640 ObjectAddress object;
18641
18642 object.classId = RelationRelationId;
18643 object.objectId = lfirst_oid(l);
18644 object.objectSubId = 0;
18645
18646 Assert(!object_address_present(&object, targetObjects));
18647
18648 add_exact_object_address(&object, targetObjects);
18649 }
18650
18651 /*
18652 * Object deletion might involve toast table access (to clean up
18653 * toasted catalog entries), so ensure we have a valid snapshot.
18654 */
18656
18657 /*
18658 * Since this is an automatic drop, rather than one directly initiated
18659 * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
18660 */
18663
18665
18666#ifdef USE_ASSERT_CHECKING
18667
18668 /*
18669 * Note that table deletion will call remove_on_commit_action, so the
18670 * entry should get marked as deleted.
18671 */
18672 foreach(l, on_commits)
18673 {
18674 OnCommitItem *oc = (OnCommitItem *) lfirst(l);
18675
18676 if (oc->oncommit != ONCOMMIT_DROP)
18677 continue;
18678
18680 }
18681#endif
18682 }
18683}
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:332
#define PERFORM_DELETION_QUIETLY
Definition: dependency.h:94
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:92
void heap_truncate(List *relids)
Definition: heap.c:3498
@ 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:271
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:669
void PopActiveSnapshot(void)
Definition: snapmgr.c:762
OnCommitAction oncommit
Definition: tablecmds.c:118
int MyXactFlags
Definition: xact.c:136
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:102

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 18761 of file tablecmds.c.

18763{
18764 char relkind;
18765 AclResult aclresult;
18766
18767 /* Nothing to do if the relation was not found. */
18768 if (!OidIsValid(relId))
18769 return;
18770
18771 /*
18772 * If the relation does exist, check whether it's an index. But note that
18773 * the relation might have been dropped between the time we did the name
18774 * lookup and now. In that case, there's nothing to do.
18775 */
18776 relkind = get_rel_relkind(relId);
18777 if (!relkind)
18778 return;
18779 if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
18780 relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
18781 ereport(ERROR,
18782 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18783 errmsg("\"%s\" is not a table or materialized view", relation->relname)));
18784
18785 /* Check permissions */
18786 aclresult = pg_class_aclcheck(relId, GetUserId(), ACL_MAINTAIN);
18787 if (aclresult != ACLCHECK_OK)
18788 aclcheck_error(aclresult,
18790 relation->relname);
18791}
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4007
#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 18821 of file tablecmds.c.

18823{
18824 HeapTuple tuple;
18825
18826 /* Nothing to do if the relation was not found. */
18827 if (!OidIsValid(relId))
18828 return;
18829
18830 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
18831 if (!HeapTupleIsValid(tuple)) /* should not happen */
18832 elog(ERROR, "cache lookup failed for relation %u", relId);
18833
18834 if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
18836 relation->relname);
18837
18838 if (!allowSystemTableMods &&
18839 IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
18840 ereport(ERROR,
18841 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
18842 errmsg("permission denied: \"%s\" is a system catalog",
18843 relation->relname)));
18844
18845 ReleaseSysCache(tuple);
18846}
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:85

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(), and ProcessUtilitySlow().

◆ register_on_commit_action()

void register_on_commit_action ( Oid  relid,
OnCommitAction  action 
)

Definition at line 18528 of file tablecmds.c.

18529{
18530 OnCommitItem *oc;
18531 MemoryContext oldcxt;
18532
18533 /*
18534 * We needn't bother registering the relation unless there is an ON COMMIT
18535 * action we need to take.
18536 */
18538 return;
18539
18541
18542 oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
18543 oc->relid = relid;
18544 oc->oncommit = action;
18547
18548 /*
18549 * We use lcons() here so that ON COMMIT actions are processed in reverse
18550 * order of registration. That might not be essential but it seems
18551 * reasonable.
18552 */
18554
18555 MemoryContextSwitchTo(oldcxt);
18556}
List * lcons(void *datum, List *list)
Definition: list.c:495
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
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(), and OnCommitItem::relid.

Referenced by heap_create_with_catalog().

◆ remove_on_commit_action()

void remove_on_commit_action ( Oid  relid)

Definition at line 18564 of file tablecmds.c.

18565{
18566 ListCell *l;
18567
18568 foreach(l, on_commits)
18569 {
18570 OnCommitItem *oc = (OnCommitItem *) lfirst(l);
18571
18572 if (oc->relid == relid)
18573 {
18575 break;
18576 }
18577 }
18578}

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 1499 of file tablecmds.c.

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

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 3970 of file tablecmds.c.

3971{
3972 Oid relid;
3974 ObjectAddress address;
3975
3976 /* lock level taken here should match renameatt_internal */
3978 stmt->missing_ok ? RVR_MISSING_OK : 0,
3980 NULL);
3981
3982 if (!OidIsValid(relid))
3983 {
3985 (errmsg("relation \"%s\" does not exist, skipping",
3986 stmt->relation->relname)));
3987 return InvalidObjectAddress;
3988 }
3989
3990 attnum =
3991 renameatt_internal(relid,
3992 stmt->subname, /* old att name */
3993 stmt->newname, /* new att name */
3994 stmt->relation->inh, /* recursive? */
3995 false, /* recursing? */
3996 0, /* expected inhcount */
3997 stmt->behavior);
3998
3999 ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
4000
4001 return address;
4002}
#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:3805
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3950

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 4117 of file tablecmds.c.

4118{
4119 Oid relid = InvalidOid;
4120 Oid typid = InvalidOid;
4121
4122 if (stmt->renameType == OBJECT_DOMCONSTRAINT)
4123 {
4124 Relation rel;
4125 HeapTuple tup;
4126
4127 typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
4128 rel = table_open(TypeRelationId, RowExclusiveLock);
4129 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
4130 if (!HeapTupleIsValid(tup))
4131 elog(ERROR, "cache lookup failed for type %u", typid);
4132 checkDomainOwner(tup);
4133 ReleaseSysCache(tup);
4134 table_close(rel, NoLock);
4135 }
4136 else
4137 {
4138 /* lock level taken here should match rename_constraint_internal */
4140 stmt->missing_ok ? RVR_MISSING_OK : 0,
4142 NULL);
4143 if (!OidIsValid(relid))
4144 {
4146 (errmsg("relation \"%s\" does not exist, skipping",
4147 stmt->relation->relname)));
4148 return InvalidObjectAddress;
4149 }
4150 }
4151
4152 return
4153 rename_constraint_internal(relid, typid,
4154 stmt->subname,
4155 stmt->newname,
4156 (stmt->relation &&
4157 stmt->relation->inh), /* recursive? */
4158 false, /* recursing? */
4159 0 /* expected inhcount */ );
4160}
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:531
#define castNode(_type_, nodeptr)
Definition: nodes.h:178
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2325
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:4008
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3473

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 4167 of file tablecmds.c.

4168{
4169 bool is_index_stmt = stmt->renameType == OBJECT_INDEX;
4170 Oid relid;
4171 ObjectAddress address;
4172
4173 /*
4174 * Grab an exclusive lock on the target table, index, sequence, view,
4175 * materialized view, or foreign table, which we will NOT release until
4176 * end of transaction.
4177 *
4178 * Lock level used here should match RenameRelationInternal, to avoid lock
4179 * escalation. However, because ALTER INDEX can be used with any relation
4180 * type, we mustn't believe without verification.
4181 */
4182 for (;;)
4183 {
4184 LOCKMODE lockmode;
4185 char relkind;
4186 bool obj_is_index;
4187
4188 lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
4189
4190 relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
4191 stmt->missing_ok ? RVR_MISSING_OK : 0,
4193 stmt);
4194
4195 if (!OidIsValid(relid))
4196 {
4198 (errmsg("relation \"%s\" does not exist, skipping",
4199 stmt->relation->relname)));
4200 return InvalidObjectAddress;
4201 }
4202
4203 /*
4204 * We allow mismatched statement and object types (e.g., ALTER INDEX
4205 * to rename a table), but we might've used the wrong lock level. If
4206 * that happens, retry with the correct lock level. We don't bother
4207 * if we already acquired AccessExclusiveLock with an index, however.
4208 */
4209 relkind = get_rel_relkind(relid);
4210 obj_is_index = (relkind == RELKIND_INDEX ||
4211 relkind == RELKIND_PARTITIONED_INDEX);
4212 if (obj_is_index || is_index_stmt == obj_is_index)
4213 break;
4214
4215 UnlockRelationOid(relid, lockmode);
4216 is_index_stmt = obj_is_index;
4217 }
4218
4219 /* Do the work */
4220 RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
4221
4222 ObjectAddressSet(address, RelationRelationId, relid);
4223
4224 return address;
4225}
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:4231

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 4231 of file tablecmds.c.

4232{
4233 Relation targetrelation;
4234 Relation relrelation; /* for RELATION relation */
4235 ItemPointerData otid;
4236 HeapTuple reltup;
4237 Form_pg_class relform;
4238 Oid namespaceId;
4239
4240 /*
4241 * Grab a lock on the target relation, which we will NOT release until end
4242 * of transaction. We need at least a self-exclusive lock so that
4243 * concurrent DDL doesn't overwrite the rename if they start updating
4244 * while still seeing the old version. The lock also guards against
4245 * triggering relcache reloads in concurrent sessions, which might not
4246 * handle this information changing under them. For indexes, we can use a
4247 * reduced lock level because RelationReloadIndexInfo() handles indexes
4248 * specially.
4249 */
4250 targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
4251 namespaceId = RelationGetNamespace(targetrelation);
4252
4253 /*
4254 * Find relation's pg_class tuple, and make sure newrelname isn't in use.
4255 */
4256 relrelation = table_open(RelationRelationId, RowExclusiveLock);
4257
4258 reltup = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(myrelid));
4259 if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4260 elog(ERROR, "cache lookup failed for relation %u", myrelid);
4261 otid = reltup->t_self;
4262 relform = (Form_pg_class) GETSTRUCT(reltup);
4263
4264 if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
4265 ereport(ERROR,
4266 (errcode(ERRCODE_DUPLICATE_TABLE),
4267 errmsg("relation \"%s\" already exists",
4268 newrelname)));
4269
4270 /*
4271 * RenameRelation is careful not to believe the caller's idea of the
4272 * relation kind being handled. We don't have to worry about this, but
4273 * let's not be totally oblivious to it. We can process an index as
4274 * not-an-index, but not the other way around.
4275 */
4276 Assert(!is_index ||
4277 is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4278 targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
4279
4280 /*
4281 * Update pg_class tuple with new relname. (Scribbling on reltup is OK
4282 * because it's a copy...)
4283 */
4284 namestrcpy(&(relform->relname), newrelname);
4285
4286 CatalogTupleUpdate(relrelation, &otid, reltup);
4287 UnlockTuple(relrelation, &otid, InplaceUpdateTupleLock);
4288
4289 InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
4290 InvalidOid, is_internal);
4291
4292 heap_freetuple(reltup);
4293 table_close(relrelation, RowExclusiveLock);
4294
4295 /*
4296 * Also rename the associated type, if any.
4297 */
4298 if (OidIsValid(targetrelation->rd_rel->reltype))
4299 RenameTypeInternal(targetrelation->rd_rel->reltype,
4300 newrelname, namespaceId);
4301
4302 /*
4303 * Also rename the associated constraint, if any.
4304 */
4305 if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4306 targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4307 {
4308 Oid constraintId = get_index_constraint(myrelid);
4309
4310 if (OidIsValid(constraintId))
4311 RenameConstraintById(constraintId, newrelname);
4312 }
4313
4314 /*
4315 * Close rel, but keep lock!
4316 */
4317 relation_close(targetrelation, NoLock);
4318}
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:765

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(), finish_heap_swap(), rename_constraint_internal(), RenameRelation(), and RenameType().

◆ ResetRelRewrite()

void ResetRelRewrite ( Oid  myrelid)

Definition at line 4324 of file tablecmds.c.

4325{
4326 Relation relrelation; /* for RELATION relation */
4327 HeapTuple reltup;
4328 Form_pg_class relform;
4329
4330 /*
4331 * Find relation's pg_class tuple.
4332 */
4333 relrelation = table_open(RelationRelationId, RowExclusiveLock);
4334
4335 reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4336 if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4337 elog(ERROR, "cache lookup failed for relation %u", myrelid);
4338 relform = (Form_pg_class) GETSTRUCT(reltup);
4339
4340 /*
4341 * Update pg_class tuple.
4342 */
4343 relform->relrewrite = InvalidOid;
4344
4345 CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4346
4347 heap_freetuple(reltup);
4348 table_close(relrelation, RowExclusiveLock);
4349}
#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 3608 of file tablecmds.c.

3609{
3610 Relation relationRelation;
3611 HeapTuple tuple;
3612 Form_pg_class classtuple;
3613
3615 ShareUpdateExclusiveLock, false) ||
3616 CheckRelationOidLockedByMe(relationId,
3617 ShareRowExclusiveLock, true));
3618
3619 /*
3620 * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3621 */
3622 relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3623 tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3624 if (!HeapTupleIsValid(tuple))
3625 elog(ERROR, "cache lookup failed for relation %u", relationId);
3626 classtuple = (Form_pg_class) GETSTRUCT(tuple);
3627
3628 if (classtuple->relhassubclass != relhassubclass)
3629 {
3630 classtuple->relhassubclass = relhassubclass;
3631 CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3632 }
3633 else
3634 {
3635 /* no need to change tuple, but force relcache rebuild anyway */
3637 }
3638
3639 heap_freetuple(tuple);
3640 table_close(relationRelation, RowExclusiveLock);
3641}
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1655
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 3711 of file tablecmds.c.

3714{
3715 Relation pg_class;
3716 HeapTuple tuple;
3717 ItemPointerData otid;
3718 Form_pg_class rd_rel;
3719 Oid reloid = RelationGetRelid(rel);
3720
3721 Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3722
3723 /* Get a modifiable copy of the relation's pg_class row. */
3724 pg_class = table_open(RelationRelationId, RowExclusiveLock);
3725
3726 tuple = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(reloid));
3727 if (!HeapTupleIsValid(tuple))
3728 elog(ERROR, "cache lookup failed for relation %u", reloid);
3729 otid = tuple->t_self;
3730 rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3731
3732 /* Update the pg_class row. */
3733 rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3734 InvalidOid : newTableSpaceId;
3735 if (RelFileNumberIsValid(newRelFilenumber))
3736 rd_rel->relfilenode = newRelFilenumber;
3737 CatalogTupleUpdate(pg_class, &otid, tuple);
3738 UnlockTuple(pg_class, &otid, InplaceUpdateTupleLock);
3739
3740 /*
3741 * Record dependency on tablespace. This is only required for relations
3742 * that have no physical storage.
3743 */
3744 if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3745 changeDependencyOnTablespace(RelationRelationId, reloid,
3746 rd_rel->reltablespace);
3747
3748 heap_freetuple(tuple);
3749 table_close(pg_class, RowExclusiveLock);
3750}
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:3654

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