PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 17817 of file tablecmds.c.

17821 {
17822  HeapTuple classTup;
17823  Form_pg_class classForm;
17824  ObjectAddress thisobj;
17825  bool already_done = false;
17826 
17827  /* no rel lock for relkind=c so use LOCKTAG_TUPLE */
17828  classTup = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(relOid));
17829  if (!HeapTupleIsValid(classTup))
17830  elog(ERROR, "cache lookup failed for relation %u", relOid);
17831  classForm = (Form_pg_class) GETSTRUCT(classTup);
17832 
17833  Assert(classForm->relnamespace == oldNspOid);
17834 
17835  thisobj.classId = RelationRelationId;
17836  thisobj.objectId = relOid;
17837  thisobj.objectSubId = 0;
17838 
17839  /*
17840  * If the object has already been moved, don't move it again. If it's
17841  * already in the right place, don't move it, but still fire the object
17842  * access hook.
17843  */
17844  already_done = object_address_present(&thisobj, objsMoved);
17845  if (!already_done && oldNspOid != newNspOid)
17846  {
17847  ItemPointerData otid = classTup->t_self;
17848 
17849  /* check for duplicate name (more friendly than unique-index failure) */
17850  if (get_relname_relid(NameStr(classForm->relname),
17851  newNspOid) != InvalidOid)
17852  ereport(ERROR,
17853  (errcode(ERRCODE_DUPLICATE_TABLE),
17854  errmsg("relation \"%s\" already exists in schema \"%s\"",
17855  NameStr(classForm->relname),
17856  get_namespace_name(newNspOid))));
17857 
17858  /* classTup is a copy, so OK to scribble on */
17859  classForm->relnamespace = newNspOid;
17860 
17861  CatalogTupleUpdate(classRel, &otid, classTup);
17862  UnlockTuple(classRel, &otid, InplaceUpdateTupleLock);
17863 
17864 
17865  /* Update dependency on schema if caller said so */
17866  if (hasDependEntry &&
17867  changeDependencyFor(RelationRelationId,
17868  relOid,
17869  NamespaceRelationId,
17870  oldNspOid,
17871  newNspOid) != 1)
17872  elog(ERROR, "could not change schema dependency for relation \"%s\"",
17873  NameStr(classForm->relname));
17874  }
17875  else
17876  UnlockTuple(classRel, &classTup->t_self, InplaceUpdateTupleLock);
17877  if (!already_done)
17878  {
17879  add_exact_object_address(&thisobj, objsMoved);
17880 
17881  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
17882  }
17883 
17884  heap_freetuple(classTup);
17885 }
#define NameStr(name)
Definition: c.h:751
#define Assert(condition)
Definition: c.h:863
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2593
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2533
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
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
Definition: lmgr.c:594
#define InplaceUpdateTupleLock
Definition: lockdefs.h:48
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1885
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
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:252
#define InvalidOid
Definition: postgres_ext.h:36
ItemPointerData t_self
Definition: htup.h:65
HeapTuple SearchSysCacheLockedCopy1(int cacheId, Datum key1)
Definition: syscache.c:399

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

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

◆ AlterTable()

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

Definition at line 4447 of file tablecmds.c.

4449 {
4450  Relation rel;
4451 
4452  /* Caller is required to provide an adequate lock. */
4453  rel = relation_open(context->relid, NoLock);
4454 
4455  CheckAlterTableIsSafe(rel);
4456 
4457  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4458 }
#define stmt
Definition: indent_codes.h:59
#define NoLock
Definition: lockdefs.h:34
tree context
Definition: radixtree.h:1835
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
static void CheckAlterTableIsSafe(Relation rel)
Definition: tablecmds.c:4362
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4783

References ATController(), CheckAlterTableIsSafe(), context, NoLock, relation_open(), and stmt.

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4521 of file tablecmds.c.

4522 {
4523  /*
4524  * This only works if we read catalog tables using MVCC snapshots.
4525  */
4526  ListCell *lcmd;
4528 
4529  foreach(lcmd, cmds)
4530  {
4531  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4532  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4533 
4534  switch (cmd->subtype)
4535  {
4536  /*
4537  * These subcommands rewrite the heap, so require full locks.
4538  */
4539  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4540  * to SELECT */
4541  case AT_SetAccessMethod: /* must rewrite heap */
4542  case AT_SetTableSpace: /* must rewrite heap */
4543  case AT_AlterColumnType: /* must rewrite heap */
4544  cmd_lockmode = AccessExclusiveLock;
4545  break;
4546 
4547  /*
4548  * These subcommands may require addition of toast tables. If
4549  * we add a toast table to a table currently being scanned, we
4550  * might miss data added to the new toast table by concurrent
4551  * insert transactions.
4552  */
4553  case AT_SetStorage: /* may add toast tables, see
4554  * ATRewriteCatalogs() */
4555  cmd_lockmode = AccessExclusiveLock;
4556  break;
4557 
4558  /*
4559  * Removing constraints can affect SELECTs that have been
4560  * optimized assuming the constraint holds true. See also
4561  * CloneFkReferenced.
4562  */
4563  case AT_DropConstraint: /* as DROP INDEX */
4564  case AT_DropNotNull: /* may change some SQL plans */
4565  cmd_lockmode = AccessExclusiveLock;
4566  break;
4567 
4568  /*
4569  * Subcommands that may be visible to concurrent SELECTs
4570  */
4571  case AT_DropColumn: /* change visible to SELECT */
4572  case AT_AddColumnToView: /* CREATE VIEW */
4573  case AT_DropOids: /* used to equiv to DropColumn */
4574  case AT_EnableAlwaysRule: /* may change SELECT rules */
4575  case AT_EnableReplicaRule: /* may change SELECT rules */
4576  case AT_EnableRule: /* may change SELECT rules */
4577  case AT_DisableRule: /* may change SELECT rules */
4578  cmd_lockmode = AccessExclusiveLock;
4579  break;
4580 
4581  /*
4582  * Changing owner may remove implicit SELECT privileges
4583  */
4584  case AT_ChangeOwner: /* change visible to SELECT */
4585  cmd_lockmode = AccessExclusiveLock;
4586  break;
4587 
4588  /*
4589  * Changing foreign table options may affect optimization.
4590  */
4591  case AT_GenericOptions:
4593  cmd_lockmode = AccessExclusiveLock;
4594  break;
4595 
4596  /*
4597  * These subcommands affect write operations only.
4598  */
4599  case AT_EnableTrig:
4600  case AT_EnableAlwaysTrig:
4601  case AT_EnableReplicaTrig:
4602  case AT_EnableTrigAll:
4603  case AT_EnableTrigUser:
4604  case AT_DisableTrig:
4605  case AT_DisableTrigAll:
4606  case AT_DisableTrigUser:
4607  cmd_lockmode = ShareRowExclusiveLock;
4608  break;
4609 
4610  /*
4611  * These subcommands affect write operations only. XXX
4612  * Theoretically, these could be ShareRowExclusiveLock.
4613  */
4614  case AT_ColumnDefault:
4616  case AT_AlterConstraint:
4617  case AT_AddIndex: /* from ADD CONSTRAINT */
4618  case AT_AddIndexConstraint:
4619  case AT_ReplicaIdentity:
4620  case AT_SetNotNull:
4621  case AT_EnableRowSecurity:
4622  case AT_DisableRowSecurity:
4623  case AT_ForceRowSecurity:
4624  case AT_NoForceRowSecurity:
4625  case AT_AddIdentity:
4626  case AT_DropIdentity:
4627  case AT_SetIdentity:
4628  case AT_SetExpression:
4629  case AT_DropExpression:
4630  case AT_SetCompression:
4631  cmd_lockmode = AccessExclusiveLock;
4632  break;
4633 
4634  case AT_AddConstraint:
4635  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4636  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4637  if (IsA(cmd->def, Constraint))
4638  {
4639  Constraint *con = (Constraint *) cmd->def;
4640 
4641  switch (con->contype)
4642  {
4643  case CONSTR_EXCLUSION:
4644  case CONSTR_PRIMARY:
4645  case CONSTR_UNIQUE:
4646 
4647  /*
4648  * Cases essentially the same as CREATE INDEX. We
4649  * could reduce the lock strength to ShareLock if
4650  * we can work out how to allow concurrent catalog
4651  * updates. XXX Might be set down to
4652  * ShareRowExclusiveLock but requires further
4653  * analysis.
4654  */
4655  cmd_lockmode = AccessExclusiveLock;
4656  break;
4657  case CONSTR_FOREIGN:
4658 
4659  /*
4660  * We add triggers to both tables when we add a
4661  * Foreign Key, so the lock level must be at least
4662  * as strong as CREATE TRIGGER.
4663  */
4664  cmd_lockmode = ShareRowExclusiveLock;
4665  break;
4666 
4667  default:
4668  cmd_lockmode = AccessExclusiveLock;
4669  }
4670  }
4671  break;
4672 
4673  /*
4674  * These subcommands affect inheritance behaviour. Queries
4675  * started before us will continue to see the old inheritance
4676  * behaviour, while queries started after we commit will see
4677  * new behaviour. No need to prevent reads or writes to the
4678  * subtable while we hook it up though. Changing the TupDesc
4679  * may be a problem, so keep highest lock.
4680  */
4681  case AT_AddInherit:
4682  case AT_DropInherit:
4683  cmd_lockmode = AccessExclusiveLock;
4684  break;
4685 
4686  /*
4687  * These subcommands affect implicit row type conversion. They
4688  * have affects similar to CREATE/DROP CAST on queries. don't
4689  * provide for invalidating parse trees as a result of such
4690  * changes, so we keep these at AccessExclusiveLock.
4691  */
4692  case AT_AddOf:
4693  case AT_DropOf:
4694  cmd_lockmode = AccessExclusiveLock;
4695  break;
4696 
4697  /*
4698  * Only used by CREATE OR REPLACE VIEW which must conflict
4699  * with an SELECTs currently using the view.
4700  */
4701  case AT_ReplaceRelOptions:
4702  cmd_lockmode = AccessExclusiveLock;
4703  break;
4704 
4705  /*
4706  * These subcommands affect general strategies for performance
4707  * and maintenance, though don't change the semantic results
4708  * from normal data reads and writes. Delaying an ALTER TABLE
4709  * behind currently active writes only delays the point where
4710  * the new strategy begins to take effect, so there is no
4711  * benefit in waiting. In this case the minimum restriction
4712  * applies: we don't currently allow concurrent catalog
4713  * updates.
4714  */
4715  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4716  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4717  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4718  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4719  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4720  cmd_lockmode = ShareUpdateExclusiveLock;
4721  break;
4722 
4723  case AT_SetLogged:
4724  case AT_SetUnLogged:
4725  cmd_lockmode = AccessExclusiveLock;
4726  break;
4727 
4728  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4729  cmd_lockmode = ShareUpdateExclusiveLock;
4730  break;
4731 
4732  /*
4733  * Rel options are more complex than first appears. Options
4734  * are set here for tables, views and indexes; for historical
4735  * reasons these can all be used with ALTER TABLE, so we can't
4736  * decide between them using the basic grammar.
4737  */
4738  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4739  * getTables() */
4740  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4741  * getTables() */
4742  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4743  break;
4744 
4745  case AT_AttachPartition:
4746  cmd_lockmode = ShareUpdateExclusiveLock;
4747  break;
4748 
4749  case AT_DetachPartition:
4750  if (((PartitionCmd *) cmd->def)->concurrent)
4751  cmd_lockmode = ShareUpdateExclusiveLock;
4752  else
4753  cmd_lockmode = AccessExclusiveLock;
4754  break;
4755 
4757  cmd_lockmode = ShareUpdateExclusiveLock;
4758  break;
4759 
4760  default: /* oops */
4761  elog(ERROR, "unrecognized alter table type: %d",
4762  (int) cmd->subtype);
4763  break;
4764  }
4765 
4766  /*
4767  * Take the greatest lockmode from any subcommand
4768  */
4769  if (cmd_lockmode > lockmode)
4770  lockmode = cmd_lockmode;
4771  }
4772 
4773  return lockmode;
4774 }
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:158
@ CONSTR_FOREIGN
Definition: parsenodes.h:2734
@ CONSTR_UNIQUE
Definition: parsenodes.h:2732
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2733
@ CONSTR_PRIMARY
Definition: parsenodes.h:2731
@ AT_AddIndexConstraint
Definition: parsenodes.h:2381
@ AT_DropOf
Definition: parsenodes.h:2412
@ AT_SetOptions
Definition: parsenodes.h:2369
@ AT_DropIdentity
Definition: parsenodes.h:2424
@ AT_DisableTrigUser
Definition: parsenodes.h:2404
@ AT_DropNotNull
Definition: parsenodes.h:2364
@ AT_AddOf
Definition: parsenodes.h:2411
@ AT_ResetOptions
Definition: parsenodes.h:2370
@ AT_ReplicaIdentity
Definition: parsenodes.h:2413
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2396
@ AT_EnableRowSecurity
Definition: parsenodes.h:2414
@ AT_AddColumnToView
Definition: parsenodes.h:2361
@ AT_ResetRelOptions
Definition: parsenodes.h:2395
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2399
@ AT_DropOids
Definition: parsenodes.h:2391
@ AT_SetIdentity
Definition: parsenodes.h:2423
@ AT_SetUnLogged
Definition: parsenodes.h:2390
@ AT_DisableTrig
Definition: parsenodes.h:2400
@ AT_SetCompression
Definition: parsenodes.h:2372
@ AT_DropExpression
Definition: parsenodes.h:2367
@ AT_AddIndex
Definition: parsenodes.h:2374
@ AT_EnableReplicaRule
Definition: parsenodes.h:2407
@ AT_DropConstraint
Definition: parsenodes.h:2382
@ AT_SetNotNull
Definition: parsenodes.h:2365
@ AT_ClusterOn
Definition: parsenodes.h:2387
@ AT_AddIdentity
Definition: parsenodes.h:2422
@ AT_ForceRowSecurity
Definition: parsenodes.h:2416
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2406
@ AT_SetAccessMethod
Definition: parsenodes.h:2392
@ AT_AlterColumnType
Definition: parsenodes.h:2384
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2421
@ AT_AddInherit
Definition: parsenodes.h:2409
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2378
@ AT_EnableTrig
Definition: parsenodes.h:2397
@ AT_DropColumn
Definition: parsenodes.h:2373
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2385
@ AT_DisableTrigAll
Definition: parsenodes.h:2402
@ AT_EnableRule
Definition: parsenodes.h:2405
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2417
@ AT_DetachPartition
Definition: parsenodes.h:2420
@ AT_SetStatistics
Definition: parsenodes.h:2368
@ AT_AttachPartition
Definition: parsenodes.h:2419
@ AT_AddConstraint
Definition: parsenodes.h:2376
@ AT_DropInherit
Definition: parsenodes.h:2410
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2398
@ AT_SetLogged
Definition: parsenodes.h:2389
@ AT_SetStorage
Definition: parsenodes.h:2371
@ AT_DisableRule
Definition: parsenodes.h:2408
@ AT_DisableRowSecurity
Definition: parsenodes.h:2415
@ AT_SetRelOptions
Definition: parsenodes.h:2394
@ AT_ChangeOwner
Definition: parsenodes.h:2386
@ AT_EnableTrigUser
Definition: parsenodes.h:2403
@ AT_SetExpression
Definition: parsenodes.h:2366
@ AT_ReAddConstraint
Definition: parsenodes.h:2377
@ AT_SetTableSpace
Definition: parsenodes.h:2393
@ AT_GenericOptions
Definition: parsenodes.h:2418
@ AT_ColumnDefault
Definition: parsenodes.h:2362
@ AT_CookedColumnDefault
Definition: parsenodes.h:2363
@ AT_AlterConstraint
Definition: parsenodes.h:2379
@ AT_EnableTrigAll
Definition: parsenodes.h:2401
@ AT_DropCluster
Definition: parsenodes.h:2388
@ AT_ValidateConstraint
Definition: parsenodes.h:2380
@ AT_AddColumn
Definition: parsenodes.h:2360
#define lfirst(lc)
Definition: pg_list.h:172
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2108
AlterTableType subtype
Definition: parsenodes.h:2438
ConstrType contype
Definition: parsenodes.h:2756
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 4476 of file tablecmds.c.

4477 {
4478  Relation rel;
4479  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4480 
4481  rel = relation_open(relid, lockmode);
4482 
4484 
4485  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4486 }
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4521

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4388 of file tablecmds.c.

4389 {
4390  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4391  stmt->missing_ok ? RVR_MISSING_OK : 0,
4393  (void *) stmt);
4394 }
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:18349

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

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 15771 of file tablecmds.c.

15772 {
15773  List *relations = NIL;
15774  ListCell *l;
15775  ScanKeyData key[1];
15776  Relation rel;
15777  TableScanDesc scan;
15778  HeapTuple tuple;
15779  Oid orig_tablespaceoid;
15780  Oid new_tablespaceoid;
15781  List *role_oids = roleSpecsToIds(stmt->roles);
15782 
15783  /* Ensure we were not asked to move something we can't */
15784  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
15785  stmt->objtype != OBJECT_MATVIEW)
15786  ereport(ERROR,
15787  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15788  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
15789 
15790  /* Get the orig and new tablespace OIDs */
15791  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
15792  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
15793 
15794  /* Can't move shared relations in to or out of pg_global */
15795  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
15796  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
15797  new_tablespaceoid == GLOBALTABLESPACE_OID)
15798  ereport(ERROR,
15799  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15800  errmsg("cannot move relations in to or out of pg_global tablespace")));
15801 
15802  /*
15803  * Must have CREATE rights on the new tablespace, unless it is the
15804  * database default tablespace (which all users implicitly have CREATE
15805  * rights on).
15806  */
15807  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
15808  {
15809  AclResult aclresult;
15810 
15811  aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
15812  ACL_CREATE);
15813  if (aclresult != ACLCHECK_OK)
15814  aclcheck_error(aclresult, OBJECT_TABLESPACE,
15815  get_tablespace_name(new_tablespaceoid));
15816  }
15817 
15818  /*
15819  * Now that the checks are done, check if we should set either to
15820  * InvalidOid because it is our database's default tablespace.
15821  */
15822  if (orig_tablespaceoid == MyDatabaseTableSpace)
15823  orig_tablespaceoid = InvalidOid;
15824 
15825  if (new_tablespaceoid == MyDatabaseTableSpace)
15826  new_tablespaceoid = InvalidOid;
15827 
15828  /* no-op */
15829  if (orig_tablespaceoid == new_tablespaceoid)
15830  return new_tablespaceoid;
15831 
15832  /*
15833  * Walk the list of objects in the tablespace and move them. This will
15834  * only find objects in our database, of course.
15835  */
15836  ScanKeyInit(&key[0],
15837  Anum_pg_class_reltablespace,
15838  BTEqualStrategyNumber, F_OIDEQ,
15839  ObjectIdGetDatum(orig_tablespaceoid));
15840 
15841  rel = table_open(RelationRelationId, AccessShareLock);
15842  scan = table_beginscan_catalog(rel, 1, key);
15843  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
15844  {
15845  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
15846  Oid relOid = relForm->oid;
15847 
15848  /*
15849  * Do not move objects in pg_catalog as part of this, if an admin
15850  * really wishes to do so, they can issue the individual ALTER
15851  * commands directly.
15852  *
15853  * Also, explicitly avoid any shared tables, temp tables, or TOAST
15854  * (TOAST will be moved with the main table).
15855  */
15856  if (IsCatalogNamespace(relForm->relnamespace) ||
15857  relForm->relisshared ||
15858  isAnyTempNamespace(relForm->relnamespace) ||
15859  IsToastNamespace(relForm->relnamespace))
15860  continue;
15861 
15862  /* Only move the object type requested */
15863  if ((stmt->objtype == OBJECT_TABLE &&
15864  relForm->relkind != RELKIND_RELATION &&
15865  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
15866  (stmt->objtype == OBJECT_INDEX &&
15867  relForm->relkind != RELKIND_INDEX &&
15868  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
15869  (stmt->objtype == OBJECT_MATVIEW &&
15870  relForm->relkind != RELKIND_MATVIEW))
15871  continue;
15872 
15873  /* Check if we are only moving objects owned by certain roles */
15874  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
15875  continue;
15876 
15877  /*
15878  * Handle permissions-checking here since we are locking the tables
15879  * and also to avoid doing a bunch of work only to fail part-way. Note
15880  * that permissions will also be checked by AlterTableInternal().
15881  *
15882  * Caller must be considered an owner on the table to move it.
15883  */
15884  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
15886  NameStr(relForm->relname));
15887 
15888  if (stmt->nowait &&
15890  ereport(ERROR,
15891  (errcode(ERRCODE_OBJECT_IN_USE),
15892  errmsg("aborting because lock on relation \"%s.%s\" is not available",
15893  get_namespace_name(relForm->relnamespace),
15894  NameStr(relForm->relname))));
15895  else
15897 
15898  /* Add to our list of objects to move */
15899  relations = lappend_oid(relations, relOid);
15900  }
15901 
15902  table_endscan(scan);
15904 
15905  if (relations == NIL)
15906  ereport(NOTICE,
15907  (errcode(ERRCODE_NO_DATA_FOUND),
15908  errmsg("no matching relations in tablespace \"%s\" found",
15909  orig_tablespaceoid == InvalidOid ? "(database default)" :
15910  get_tablespace_name(orig_tablespaceoid))));
15911 
15912  /* Everything is locked, loop through and move all of the relations. */
15913  foreach(l, relations)
15914  {
15915  List *cmds = NIL;
15917 
15918  cmd->subtype = AT_SetTableSpace;
15919  cmd->name = stmt->new_tablespacename;
15920 
15921  cmds = lappend(cmds, cmd);
15922 
15924  /* OID is set by AlterTableInternal */
15925  AlterTableInternal(lfirst_oid(l), cmds, false);
15927  }
15928 
15929  return new_tablespaceoid;
15930 }
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:3810
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4064
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:780
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:1243
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:150
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:2003
Oid GetUserId(void)
Definition: miscinit.c:524
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3687
#define makeNode(_type_)
Definition: nodes.h:155
ObjectType get_relkind_objtype(char relkind)
@ OBJECT_MATVIEW
Definition: parsenodes.h:2291
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2310
@ OBJECT_INDEX
Definition: parsenodes.h:2288
@ OBJECT_TABLE
Definition: parsenodes.h:2309
#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:31
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:129
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:112
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:1028
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4476
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 17709 of file tablecmds.c.

17710 {
17711  Relation rel;
17712  Oid relid;
17713  Oid oldNspOid;
17714  Oid nspOid;
17715  RangeVar *newrv;
17716  ObjectAddresses *objsMoved;
17717  ObjectAddress myself;
17718 
17720  stmt->missing_ok ? RVR_MISSING_OK : 0,
17722  (void *) stmt);
17723 
17724  if (!OidIsValid(relid))
17725  {
17726  ereport(NOTICE,
17727  (errmsg("relation \"%s\" does not exist, skipping",
17728  stmt->relation->relname)));
17729  return InvalidObjectAddress;
17730  }
17731 
17732  rel = relation_open(relid, NoLock);
17733 
17734  oldNspOid = RelationGetNamespace(rel);
17735 
17736  /* If it's an owned sequence, disallow moving it by itself. */
17737  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
17738  {
17739  Oid tableId;
17740  int32 colId;
17741 
17742  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
17743  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
17744  ereport(ERROR,
17745  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17746  errmsg("cannot move an owned sequence into another schema"),
17747  errdetail("Sequence \"%s\" is linked to table \"%s\".",
17749  get_rel_name(tableId))));
17750  }
17751 
17752  /* Get and lock schema OID and check its permissions. */
17753  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
17754  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
17755 
17756  /* common checks on switching namespaces */
17757  CheckSetNamespace(oldNspOid, nspOid);
17758 
17759  objsMoved = new_object_addresses();
17760  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
17761  free_object_addresses(objsMoved);
17762 
17763  ObjectAddressSet(myself, RelationRelationId, relid);
17764 
17765  if (oldschema)
17766  *oldschema = oldNspOid;
17767 
17768  /* close rel, but keep lock until commit */
17769  relation_close(rel, NoLock);
17770 
17771  return myself;
17772 }
signed int int32
Definition: c.h:508
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2487
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2773
@ 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:1928
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:424
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:539
#define RelationGetNamespace(relation)
Definition: rel.h:546
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:17780

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

17782 {
17783  Relation classRel;
17784 
17785  Assert(objsMoved != NULL);
17786 
17787  /* OK, modify the pg_class row and pg_depend entry */
17788  classRel = table_open(RelationRelationId, RowExclusiveLock);
17789 
17790  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
17791  nspOid, true, objsMoved);
17792 
17793  /* Fix the table's row type too, if it has one */
17794  if (OidIsValid(rel->rd_rel->reltype))
17795  AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid,
17796  false, /* isImplicitArray */
17797  false, /* ignoreDependent */
17798  false, /* errorOnTableType */
17799  objsMoved);
17800 
17801  /* Fix other dependent stuff */
17802  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
17803  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
17804  objsMoved, AccessExclusiveLock);
17805  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
17806  false, objsMoved);
17807 
17808  table_close(classRel, RowExclusiveLock);
17809 }
#define RowExclusiveLock
Definition: lockdefs.h:38
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
#define RelationGetRelid(relation)
Definition: rel.h:505
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17817
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:17939
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17894
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:4162

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

18224 {
18225  ListCell *cur_item;
18226 
18227  foreach(cur_item, on_commits)
18228  {
18229  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
18230 
18231  if (!isCommit && oc->creating_subid == mySubid)
18232  {
18233  /* cur_item must be removed */
18235  pfree(oc);
18236  }
18237  else
18238  {
18239  /* cur_item must be preserved */
18240  if (oc->creating_subid == mySubid)
18241  oc->creating_subid = parentSubid;
18242  if (oc->deleting_subid == mySubid)
18243  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
18244  }
18245  }
18246 }
#define InvalidSubTransactionId
Definition: c.h:663
void pfree(void *pointer)
Definition: mcxt.c:1521
#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 18190 of file tablecmds.c.

18191 {
18192  ListCell *cur_item;
18193 
18194  foreach(cur_item, on_commits)
18195  {
18196  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
18197 
18198  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
18200  {
18201  /* cur_item must be removed */
18203  pfree(oc);
18204  }
18205  else
18206  {
18207  /* cur_item must be preserved */
18210  }
18211  }
18212 }

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

14863 {
14864  Relation target_rel;
14865  Relation class_rel;
14866  HeapTuple tuple;
14867  Form_pg_class tuple_class;
14868 
14869  /*
14870  * Get exclusive lock till end of transaction on the target table. Use
14871  * relation_open so that we can work on indexes and sequences.
14872  */
14873  target_rel = relation_open(relationOid, lockmode);
14874 
14875  /* Get its pg_class tuple, too */
14876  class_rel = table_open(RelationRelationId, RowExclusiveLock);
14877 
14878  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
14879  if (!HeapTupleIsValid(tuple))
14880  elog(ERROR, "cache lookup failed for relation %u", relationOid);
14881  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
14882 
14883  /* Can we change the ownership of this tuple? */
14884  switch (tuple_class->relkind)
14885  {
14886  case RELKIND_RELATION:
14887  case RELKIND_VIEW:
14888  case RELKIND_MATVIEW:
14889  case RELKIND_FOREIGN_TABLE:
14890  case RELKIND_PARTITIONED_TABLE:
14891  /* ok to change owner */
14892  break;
14893  case RELKIND_INDEX:
14894  if (!recursing)
14895  {
14896  /*
14897  * Because ALTER INDEX OWNER used to be allowed, and in fact
14898  * is generated by old versions of pg_dump, we give a warning
14899  * and do nothing rather than erroring out. Also, to avoid
14900  * unnecessary chatter while restoring those old dumps, say
14901  * nothing at all if the command would be a no-op anyway.
14902  */
14903  if (tuple_class->relowner != newOwnerId)
14904  ereport(WARNING,
14905  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14906  errmsg("cannot change owner of index \"%s\"",
14907  NameStr(tuple_class->relname)),
14908  errhint("Change the ownership of the index's table instead.")));
14909  /* quick hack to exit via the no-op path */
14910  newOwnerId = tuple_class->relowner;
14911  }
14912  break;
14913  case RELKIND_PARTITIONED_INDEX:
14914  if (recursing)
14915  break;
14916  ereport(ERROR,
14917  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14918  errmsg("cannot change owner of index \"%s\"",
14919  NameStr(tuple_class->relname)),
14920  errhint("Change the ownership of the index's table instead.")));
14921  break;
14922  case RELKIND_SEQUENCE:
14923  if (!recursing &&
14924  tuple_class->relowner != newOwnerId)
14925  {
14926  /* if it's an owned sequence, disallow changing it by itself */
14927  Oid tableId;
14928  int32 colId;
14929 
14930  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
14931  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
14932  ereport(ERROR,
14933  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14934  errmsg("cannot change owner of sequence \"%s\"",
14935  NameStr(tuple_class->relname)),
14936  errdetail("Sequence \"%s\" is linked to table \"%s\".",
14937  NameStr(tuple_class->relname),
14938  get_rel_name(tableId))));
14939  }
14940  break;
14941  case RELKIND_COMPOSITE_TYPE:
14942  if (recursing)
14943  break;
14944  ereport(ERROR,
14945  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14946  errmsg("\"%s\" is a composite type",
14947  NameStr(tuple_class->relname)),
14948  /* translator: %s is an SQL ALTER command */
14949  errhint("Use %s instead.",
14950  "ALTER TYPE")));
14951  break;
14952  case RELKIND_TOASTVALUE:
14953  if (recursing)
14954  break;
14955  /* FALL THRU */
14956  default:
14957  ereport(ERROR,
14958  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14959  errmsg("cannot change owner of relation \"%s\"",
14960  NameStr(tuple_class->relname)),
14961  errdetail_relkind_not_supported(tuple_class->relkind)));
14962  }
14963 
14964  /*
14965  * If the new owner is the same as the existing owner, consider the
14966  * command to have succeeded. This is for dump restoration purposes.
14967  */
14968  if (tuple_class->relowner != newOwnerId)
14969  {
14970  Datum repl_val[Natts_pg_class];
14971  bool repl_null[Natts_pg_class];
14972  bool repl_repl[Natts_pg_class];
14973  Acl *newAcl;
14974  Datum aclDatum;
14975  bool isNull;
14976  HeapTuple newtuple;
14977 
14978  /* skip permission checks when recursing to index or toast table */
14979  if (!recursing)
14980  {
14981  /* Superusers can always do it */
14982  if (!superuser())
14983  {
14984  Oid namespaceOid = tuple_class->relnamespace;
14985  AclResult aclresult;
14986 
14987  /* Otherwise, must be owner of the existing object */
14988  if (!object_ownercheck(RelationRelationId, relationOid, GetUserId()))
14990  RelationGetRelationName(target_rel));
14991 
14992  /* Must be able to become new owner */
14993  check_can_set_role(GetUserId(), newOwnerId);
14994 
14995  /* New owner must have CREATE privilege on namespace */
14996  aclresult = object_aclcheck(NamespaceRelationId, namespaceOid, newOwnerId,
14997  ACL_CREATE);
14998  if (aclresult != ACLCHECK_OK)
14999  aclcheck_error(aclresult, OBJECT_SCHEMA,
15000  get_namespace_name(namespaceOid));
15001  }
15002  }
15003 
15004  memset(repl_null, false, sizeof(repl_null));
15005  memset(repl_repl, false, sizeof(repl_repl));
15006 
15007  repl_repl[Anum_pg_class_relowner - 1] = true;
15008  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
15009 
15010  /*
15011  * Determine the modified ACL for the new owner. This is only
15012  * necessary when the ACL is non-null.
15013  */
15014  aclDatum = SysCacheGetAttr(RELOID, tuple,
15015  Anum_pg_class_relacl,
15016  &isNull);
15017  if (!isNull)
15018  {
15019  newAcl = aclnewowner(DatumGetAclP(aclDatum),
15020  tuple_class->relowner, newOwnerId);
15021  repl_repl[Anum_pg_class_relacl - 1] = true;
15022  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
15023  }
15024 
15025  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
15026 
15027  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
15028 
15029  heap_freetuple(newtuple);
15030 
15031  /*
15032  * We must similarly update any per-column ACLs to reflect the new
15033  * owner; for neatness reasons that's split out as a subroutine.
15034  */
15035  change_owner_fix_column_acls(relationOid,
15036  tuple_class->relowner,
15037  newOwnerId);
15038 
15039  /*
15040  * Update owner dependency reference, if any. A composite type has
15041  * none, because it's tracked for the pg_type entry instead of here;
15042  * indexes and TOAST tables don't have their own entries either.
15043  */
15044  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
15045  tuple_class->relkind != RELKIND_INDEX &&
15046  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
15047  tuple_class->relkind != RELKIND_TOASTVALUE)
15048  changeDependencyOnOwner(RelationRelationId, relationOid,
15049  newOwnerId);
15050 
15051  /*
15052  * Also change the ownership of the table's row type, if it has one
15053  */
15054  if (OidIsValid(tuple_class->reltype))
15055  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
15056 
15057  /*
15058  * If we are operating on a table or materialized view, also change
15059  * the ownership of any indexes and sequences that belong to the
15060  * relation, as well as its toast table (if it has one).
15061  */
15062  if (tuple_class->relkind == RELKIND_RELATION ||
15063  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
15064  tuple_class->relkind == RELKIND_MATVIEW ||
15065  tuple_class->relkind == RELKIND_TOASTVALUE)
15066  {
15067  List *index_oid_list;
15068  ListCell *i;
15069 
15070  /* Find all the indexes belonging to this relation */
15071  index_oid_list = RelationGetIndexList(target_rel);
15072 
15073  /* For each index, recursively change its ownership */
15074  foreach(i, index_oid_list)
15075  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
15076 
15077  list_free(index_oid_list);
15078  }
15079 
15080  /* If it has a toast table, recurse to change its ownership */
15081  if (tuple_class->reltoastrelid != InvalidOid)
15082  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
15083  true, lockmode);
15084 
15085  /* If it has dependent sequences, recurse to change them too */
15086  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
15087  }
15088 
15089  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
15090 
15091  ReleaseSysCache(tuple);
15092  table_close(class_rel, RowExclusiveLock);
15093  relation_close(target_rel, NoLock);
15094 }
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:1209
int i
Definition: isn.c:72
void list_free(List *list)
Definition: list.c:1546
@ OBJECT_SCHEMA
Definition: parsenodes.h:2304
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:322
uintptr_t Datum
Definition: postgres.h:64
#define RelationGetDescr(relation)
Definition: rel.h:531
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4767
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:595
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:14862
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:15168
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:15103
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3993

References ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, aclnewowner(), AlterTypeOwnerInternal(), 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(), ATExecCmd(), change_owner_recurse_to_sequences(), and shdepReassignOwned_Owner().

◆ BuildDescForRelation()

TupleDesc BuildDescForRelation ( const List columns)

Definition at line 1328 of file tablecmds.c.

1329 {
1330  int natts;
1332  ListCell *l;
1333  TupleDesc desc;
1334  char *attname;
1335  Oid atttypid;
1336  int32 atttypmod;
1337  Oid attcollation;
1338  int attdim;
1339 
1340  /*
1341  * allocate a new tuple descriptor
1342  */
1343  natts = list_length(columns);
1344  desc = CreateTemplateTupleDesc(natts);
1345 
1346  attnum = 0;
1347 
1348  foreach(l, columns)
1349  {
1350  ColumnDef *entry = lfirst(l);
1351  AclResult aclresult;
1352  Form_pg_attribute att;
1353 
1354  /*
1355  * for each entry in the list, get the name and type information from
1356  * the list and have TupleDescInitEntry fill in the attribute
1357  * information we need.
1358  */
1359  attnum++;
1360 
1361  attname = entry->colname;
1362  typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
1363 
1364  aclresult = object_aclcheck(TypeRelationId, atttypid, GetUserId(), ACL_USAGE);
1365  if (aclresult != ACLCHECK_OK)
1366  aclcheck_error_type(aclresult, atttypid);
1367 
1368  attcollation = GetColumnDefCollation(NULL, entry, atttypid);
1369  attdim = list_length(entry->typeName->arrayBounds);
1370  if (attdim > PG_INT16_MAX)
1371  ereport(ERROR,
1372  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1373  errmsg("too many array dimensions"));
1374 
1375  if (entry->typeName->setof)
1376  ereport(ERROR,
1377  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
1378  errmsg("column \"%s\" cannot be declared SETOF",
1379  attname)));
1380 
1382  atttypid, atttypmod, attdim);
1383  att = TupleDescAttr(desc, attnum - 1);
1384 
1385  /* Override TupleDescInitEntry's settings as requested */
1386  TupleDescInitEntryCollation(desc, attnum, attcollation);
1387 
1388  /* Fill in additional stuff not handled by TupleDescInitEntry */
1389  att->attnotnull = entry->is_not_null;
1390  att->attislocal = entry->is_local;
1391  att->attinhcount = entry->inhcount;
1392  att->attidentity = entry->identity;
1393  att->attgenerated = entry->generated;
1394  att->attcompression = GetAttributeCompression(att->atttypid, entry->compression);
1395  if (entry->storage)
1396  att->attstorage = entry->storage;
1397  else if (entry->storage_name)
1398  att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name);
1399  }
1400 
1401  return desc;
1402 }
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:591
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:209
static int list_length(const List *l)
Definition: pg_list.h:152
bool is_not_null
Definition: parsenodes.h:733
char identity
Definition: parsenodes.h:739
char * storage_name
Definition: parsenodes.h:736
char * colname
Definition: parsenodes.h:728
TypeName * typeName
Definition: parsenodes.h:729
char generated
Definition: parsenodes.h:742
char storage
Definition: parsenodes.h:735
bool is_local
Definition: parsenodes.h:732
int16 inhcount
Definition: parsenodes.h:731
char * compression
Definition: parsenodes.h:730
bool setof
Definition: parsenodes.h:272
List * arrayBounds
Definition: parsenodes.h:276
static char GetAttributeCompression(Oid atttypid, const char *compression)
Definition: tablecmds.c:20741
static char GetAttributeStorage(Oid atttypid, const char *storagemode)
Definition: tablecmds.c:20779
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67
void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid)
Definition: tupdesc.c:833
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:651
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

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

6992 {
6993  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
6994  bool typeOk = false;
6995 
6996  if (typ->typtype == TYPTYPE_COMPOSITE)
6997  {
6998  Relation typeRelation;
6999 
7000  Assert(OidIsValid(typ->typrelid));
7001  typeRelation = relation_open(typ->typrelid, AccessShareLock);
7002  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
7003 
7004  /*
7005  * Close the parent rel, but keep our AccessShareLock on it until xact
7006  * commit. That will prevent someone else from deleting or ALTERing
7007  * the type before the typed table creation/conversion commits.
7008  */
7009  relation_close(typeRelation, NoLock);
7010 
7011  if (!typeOk)
7012  ereport(ERROR,
7013  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7014  errmsg("type %s is the row type of another table",
7015  format_type_be(typ->oid)),
7016  errdetail("A typed table must use a stand-alone composite type created with CREATE TYPE.")));
7017  }
7018  else
7019  ereport(ERROR,
7020  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7021  errmsg("type %s is not a composite type",
7022  format_type_be(typ->oid))));
7023 }
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 3606 of file tablecmds.c.

3607 {
3608  Oid oldTableSpaceId;
3609 
3610  /*
3611  * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3612  * stored as 0.
3613  */
3614  oldTableSpaceId = rel->rd_rel->reltablespace;
3615  if (newTableSpaceId == oldTableSpaceId ||
3616  (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3617  return false;
3618 
3619  /*
3620  * We cannot support moving mapped relations into different tablespaces.
3621  * (In particular this eliminates all shared catalogs.)
3622  */
3623  if (RelationIsMapped(rel))
3624  ereport(ERROR,
3625  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3626  errmsg("cannot move system relation \"%s\"",
3627  RelationGetRelationName(rel))));
3628 
3629  /* Cannot move a non-shared relation into pg_global */
3630  if (newTableSpaceId == GLOBALTABLESPACE_OID)
3631  ereport(ERROR,
3632  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3633  errmsg("only shared relations can be placed in pg_global tablespace")));
3634 
3635  /*
3636  * Do not allow moving temp tables of other backends ... their local
3637  * buffer manager is not going to cope.
3638  */
3639  if (RELATION_IS_OTHER_TEMP(rel))
3640  ereport(ERROR,
3641  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3642  errmsg("cannot move temporary tables of other sessions")));
3643 
3644  return true;
3645 }
#define RelationIsMapped(relation)
Definition: rel.h:554
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:658

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

4330 {
4331  int expected_refcnt;
4332 
4333  expected_refcnt = rel->rd_isnailed ? 2 : 1;
4334  if (rel->rd_refcnt != expected_refcnt)
4335  ereport(ERROR,
4336  (errcode(ERRCODE_OBJECT_IN_USE),
4337  /* translator: first %s is a SQL command, eg ALTER TABLE */
4338  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
4339  stmt, RelationGetRelationName(rel))));
4340 
4341  if (rel->rd_rel->relkind != RELKIND_INDEX &&
4342  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
4344  ereport(ERROR,
4345  (errcode(ERRCODE_OBJECT_IN_USE),
4346  /* translator: first %s is a SQL command, eg ALTER TABLE */
4347  errmsg("cannot %s \"%s\" because it has pending trigger events",
4348  stmt, RelationGetRelationName(rel))));
4349 }
int rd_refcnt
Definition: rel.h:59
bool rd_isnailed
Definition: rel.h:62
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5980

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

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

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_local, CookedConstraint::is_no_inherit, lappend(), lappend_oid(), lfirst, lfirst_oid, linitial_oid, list_concat(), list_free(), list_length(), list_member_oid(), make_parsestate(), MergeAttributes(), RawColumnDefault::missingMode, MyDatabaseTableSpace, CookedConstraint::name, NAMEDATALEN, NIL, NoLock, object_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, TupleDescAttr, typenameTypeId(), and view_reloptions().

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

◆ ExecuteTruncate()

void ExecuteTruncate ( TruncateStmt stmt)

Definition at line 1807 of file tablecmds.c.

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

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

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

6786 {
6787  Relation depRel;
6788  ScanKeyData key[2];
6789  SysScanDesc depScan;
6790  HeapTuple depTup;
6791 
6792  /* since this function recurses, it could be driven to stack overflow */
6794 
6795  /*
6796  * We scan pg_depend to find those things that depend on the given type.
6797  * (We assume we can ignore refobjsubid for a type.)
6798  */
6799  depRel = table_open(DependRelationId, AccessShareLock);
6800 
6801  ScanKeyInit(&key[0],
6802  Anum_pg_depend_refclassid,
6803  BTEqualStrategyNumber, F_OIDEQ,
6804  ObjectIdGetDatum(TypeRelationId));
6805  ScanKeyInit(&key[1],
6806  Anum_pg_depend_refobjid,
6807  BTEqualStrategyNumber, F_OIDEQ,
6808  ObjectIdGetDatum(typeOid));
6809 
6810  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6811  NULL, 2, key);
6812 
6813  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6814  {
6815  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6816  Relation rel;
6817  TupleDesc tupleDesc;
6818  Form_pg_attribute att;
6819 
6820  /* Check for directly dependent types */
6821  if (pg_depend->classid == TypeRelationId)
6822  {
6823  /*
6824  * This must be an array, domain, or range containing the given
6825  * type, so recursively check for uses of this type. Note that
6826  * any error message will mention the original type not the
6827  * container; this is intentional.
6828  */
6829  find_composite_type_dependencies(pg_depend->objid,
6830  origRelation, origTypeName);
6831  continue;
6832  }
6833 
6834  /* Else, ignore dependees that aren't relations */
6835  if (pg_depend->classid != RelationRelationId)
6836  continue;
6837 
6838  rel = relation_open(pg_depend->objid, AccessShareLock);
6839  tupleDesc = RelationGetDescr(rel);
6840 
6841  /*
6842  * If objsubid identifies a specific column, refer to that in error
6843  * messages. Otherwise, search to see if there's a user column of the
6844  * type. (We assume system columns are never of interesting types.)
6845  * The search is needed because an index containing an expression
6846  * column of the target type will just be recorded as a whole-relation
6847  * dependency. If we do not find a column of the type, the dependency
6848  * must indicate that the type is transiently referenced in an index
6849  * expression but not stored on disk, which we assume is OK, just as
6850  * we do for references in views. (It could also be that the target
6851  * type is embedded in some container type that is stored in an index
6852  * column, but the previous recursion should catch such cases.)
6853  */
6854  if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
6855  att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
6856  else
6857  {
6858  att = NULL;
6859  for (int attno = 1; attno <= tupleDesc->natts; attno++)
6860  {
6861  att = TupleDescAttr(tupleDesc, attno - 1);
6862  if (att->atttypid == typeOid && !att->attisdropped)
6863  break;
6864  att = NULL;
6865  }
6866  if (att == NULL)
6867  {
6868  /* No such column, so assume OK */
6870  continue;
6871  }
6872  }
6873 
6874  /*
6875  * We definitely should reject if the relation has storage. If it's
6876  * partitioned, then perhaps we don't have to reject: if there are
6877  * partitions then we'll fail when we find one, else there is no
6878  * stored data to worry about. However, it's possible that the type
6879  * change would affect conclusions about whether the type is sortable
6880  * or hashable and thus (if it's a partitioning column) break the
6881  * partitioning rule. For now, reject for partitioned rels too.
6882  */
6883  if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
6884  RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
6885  {
6886  if (origTypeName)
6887  ereport(ERROR,
6888  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6889  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6890  origTypeName,
6892  NameStr(att->attname))));
6893  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6894  ereport(ERROR,
6895  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6896  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6897  RelationGetRelationName(origRelation),
6899  NameStr(att->attname))));
6900  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
6901  ereport(ERROR,
6902  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6903  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
6904  RelationGetRelationName(origRelation),
6906  NameStr(att->attname))));
6907  else
6908  ereport(ERROR,
6909  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6910  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
6911  RelationGetRelationName(origRelation),
6913  NameStr(att->attname))));
6914  }
6915  else if (OidIsValid(rel->rd_rel->reltype))
6916  {
6917  /*
6918  * A view or composite type itself isn't a problem, but we must
6919  * recursively check for indirect dependencies via its rowtype.
6920  */
6922  origRelation, origTypeName);
6923  }
6924 
6926  }
6927 
6928  systable_endscan(depScan);
6929 
6931 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:511
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
void check_stack_depth(void)
Definition: postgres.c:3563
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:6784

References AccessShareLock, BTEqualStrategyNumber, check_stack_depth(), ereport, errcode(), errmsg(), ERROR, 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(), and get_rels_with_domain().

◆ PartConstraintImpliedByRelConstraint()

bool PartConstraintImpliedByRelConstraint ( Relation  scanrel,
List partConstraint 
)

Definition at line 18806 of file tablecmds.c.

18808 {
18809  List *existConstraint = NIL;
18810  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
18811  int i;
18812 
18813  if (constr && constr->has_not_null)
18814  {
18815  int natts = scanrel->rd_att->natts;
18816 
18817  for (i = 1; i <= natts; i++)
18818  {
18819  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
18820 
18821  if (att->attnotnull && !att->attisdropped)
18822  {
18823  NullTest *ntest = makeNode(NullTest);
18824 
18825  ntest->arg = (Expr *) makeVar(1,
18826  i,
18827  att->atttypid,
18828  att->atttypmod,
18829  att->attcollation,
18830  0);
18831  ntest->nulltesttype = IS_NOT_NULL;
18832 
18833  /*
18834  * argisrow=false is correct even for a composite column,
18835  * because attnotnull does not represent a SQL-spec IS NOT
18836  * NULL test in such a case, just IS DISTINCT FROM NULL.
18837  */
18838  ntest->argisrow = false;
18839  ntest->location = -1;
18840  existConstraint = lappend(existConstraint, ntest);
18841  }
18842  }
18843  }
18844 
18845  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
18846 }
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
@ IS_NOT_NULL
Definition: primnodes.h:1952
NullTestType nulltesttype
Definition: primnodes.h:1959
ParseLoc location
Definition: primnodes.h:1962
Expr * arg
Definition: primnodes.h:1958
TupleDesc rd_att
Definition: rel.h:112
bool has_not_null
Definition: tupdesc.h:44
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:18859

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

18084 {
18085  ListCell *l;
18086  List *oids_to_truncate = NIL;
18087  List *oids_to_drop = NIL;
18088 
18089  foreach(l, on_commits)
18090  {
18091  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
18092 
18093  /* Ignore entry if already dropped in this xact */
18095  continue;
18096 
18097  switch (oc->oncommit)
18098  {
18099  case ONCOMMIT_NOOP:
18101  /* Do nothing (there shouldn't be such entries, actually) */
18102  break;
18103  case ONCOMMIT_DELETE_ROWS:
18104 
18105  /*
18106  * If this transaction hasn't accessed any temporary
18107  * relations, we can skip truncating ON COMMIT DELETE ROWS
18108  * tables, as they must still be empty.
18109  */
18111  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
18112  break;
18113  case ONCOMMIT_DROP:
18114  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
18115  break;
18116  }
18117  }
18118 
18119  /*
18120  * Truncate relations before dropping so that all dependencies between
18121  * relations are removed after they are worked on. Doing it like this
18122  * might be a waste as it is possible that a relation being truncated will
18123  * be dropped anyway due to its parent being dropped, but this makes the
18124  * code more robust because of not having to re-check that the relation
18125  * exists at truncation time.
18126  */
18127  if (oids_to_truncate != NIL)
18128  heap_truncate(oids_to_truncate);
18129 
18130  if (oids_to_drop != NIL)
18131  {
18132  ObjectAddresses *targetObjects = new_object_addresses();
18133 
18134  foreach(l, oids_to_drop)
18135  {
18136  ObjectAddress object;
18137 
18138  object.classId = RelationRelationId;
18139  object.objectId = lfirst_oid(l);
18140  object.objectSubId = 0;
18141 
18142  Assert(!object_address_present(&object, targetObjects));
18143 
18144  add_exact_object_address(&object, targetObjects);
18145  }
18146 
18147  /*
18148  * Object deletion might involve toast table access (to clean up
18149  * toasted catalog entries), so ensure we have a valid snapshot.
18150  */
18152 
18153  /*
18154  * Since this is an automatic drop, rather than one directly initiated
18155  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
18156  */
18157  performMultipleDeletions(targetObjects, DROP_CASCADE,
18159 
18161 
18162 #ifdef USE_ASSERT_CHECKING
18163 
18164  /*
18165  * Note that table deletion will call remove_on_commit_action, so the
18166  * entry should get marked as deleted.
18167  */
18168  foreach(l, on_commits)
18169  {
18170  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
18171 
18172  if (oc->oncommit != ONCOMMIT_DROP)
18173  continue;
18174 
18176  }
18177 #endif
18178  }
18179 }
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:3406
@ ONCOMMIT_DELETE_ROWS
Definition: primnodes.h:59
@ ONCOMMIT_PRESERVE_ROWS
Definition: primnodes.h:58
@ ONCOMMIT_DROP
Definition: primnodes.h:60
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:216
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:648
void PopActiveSnapshot(void)
Definition: snapmgr.c:743
OnCommitAction oncommit
Definition: tablecmds.c:118
int MyXactFlags
Definition: xact.c:135
#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 18257 of file tablecmds.c.

18259 {
18260  char relkind;
18261  AclResult aclresult;
18262 
18263  /* Nothing to do if the relation was not found. */
18264  if (!OidIsValid(relId))
18265  return;
18266 
18267  /*
18268  * If the relation does exist, check whether it's an index. But note that
18269  * the relation might have been dropped between the time we did the name
18270  * lookup and now. In that case, there's nothing to do.
18271  */
18272  relkind = get_rel_relkind(relId);
18273  if (!relkind)
18274  return;
18275  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
18276  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
18277  ereport(ERROR,
18278  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
18279  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
18280 
18281  /* Check permissions */
18282  aclresult = pg_class_aclcheck(relId, GetUserId(), ACL_MAINTAIN);
18283  if (aclresult != ACLCHECK_OK)
18284  aclcheck_error(aclresult,
18286  relation->relname);
18287 }
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4013
#define ACL_MAINTAIN
Definition: parsenodes.h:90
char * relname
Definition: primnodes.h:82

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

18319 {
18320  HeapTuple tuple;
18321 
18322  /* Nothing to do if the relation was not found. */
18323  if (!OidIsValid(relId))
18324  return;
18325 
18326  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
18327  if (!HeapTupleIsValid(tuple)) /* should not happen */
18328  elog(ERROR, "cache lookup failed for relation %u", relId);
18329 
18330  if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
18332  relation->relname);
18333 
18334  if (!allowSystemTableMods &&
18335  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
18336  ereport(ERROR,
18337  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
18338  errmsg("permission denied: \"%s\" is a system catalog",
18339  relation->relname)));
18340 
18341  ReleaseSysCache(tuple);
18342 }
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 18024 of file tablecmds.c.

18025 {
18026  OnCommitItem *oc;
18027  MemoryContext oldcxt;
18028 
18029  /*
18030  * We needn't bother registering the relation unless there is an ON COMMIT
18031  * action we need to take.
18032  */
18034  return;
18035 
18037 
18038  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
18039  oc->relid = relid;
18040  oc->oncommit = action;
18043 
18044  /*
18045  * We use lcons() here so that ON COMMIT actions are processed in reverse
18046  * order of registration. That might not be essential but it seems
18047  * reasonable.
18048  */
18049  on_commits = lcons(oc, on_commits);
18050 
18051  MemoryContextSwitchTo(oldcxt);
18052 }
List * lcons(void *datum, List *list)
Definition: list.c:495
MemoryContext CacheMemoryContext
Definition: mcxt.c:152
MemoryContextSwitchTo(old_ctx)

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

18061 {
18062  ListCell *l;
18063 
18064  foreach(l, on_commits)
18065  {
18066  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
18067 
18068  if (oc->relid == relid)
18069  {
18071  break;
18072  }
18073  }
18074 }

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

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

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

3923 {
3924  Oid relid;
3926  ObjectAddress address;
3927 
3928  /* lock level taken here should match renameatt_internal */
3930  stmt->missing_ok ? RVR_MISSING_OK : 0,
3932  NULL);
3933 
3934  if (!OidIsValid(relid))
3935  {
3936  ereport(NOTICE,
3937  (errmsg("relation \"%s\" does not exist, skipping",
3938  stmt->relation->relname)));
3939  return InvalidObjectAddress;
3940  }
3941 
3942  attnum =
3943  renameatt_internal(relid,
3944  stmt->subname, /* old att name */
3945  stmt->newname, /* new att name */
3946  stmt->relation->inh, /* recursive? */
3947  false, /* recursing? */
3948  0, /* expected inhcount */
3949  stmt->behavior);
3950 
3951  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3952 
3953  return address;
3954 }
#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:3757
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3902

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

4070 {
4071  Oid relid = InvalidOid;
4072  Oid typid = InvalidOid;
4073 
4074  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
4075  {
4076  Relation rel;
4077  HeapTuple tup;
4078 
4079  typid = typenameTypeId(NULL, makeTypeNameFromNameList(castNode(List, stmt->object)));
4080  rel = table_open(TypeRelationId, RowExclusiveLock);
4081  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
4082  if (!HeapTupleIsValid(tup))
4083  elog(ERROR, "cache lookup failed for type %u", typid);
4084  checkDomainOwner(tup);
4085  ReleaseSysCache(tup);
4086  table_close(rel, NoLock);
4087  }
4088  else
4089  {
4090  /* lock level taken here should match rename_constraint_internal */
4092  stmt->missing_ok ? RVR_MISSING_OK : 0,
4094  NULL);
4095  if (!OidIsValid(relid))
4096  {
4097  ereport(NOTICE,
4098  (errmsg("relation \"%s\" does not exist, skipping",
4099  stmt->relation->relname)));
4100  return InvalidObjectAddress;
4101  }
4102  }
4103 
4104  return
4105  rename_constraint_internal(relid, typid,
4106  stmt->subname,
4107  stmt->newname,
4108  (stmt->relation &&
4109  stmt->relation->inh), /* recursive? */
4110  false, /* recursing? */
4111  0 /* expected inhcount */ );
4112 }
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:481
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2281
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:3960
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3494

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

4120 {
4121  bool is_index_stmt = stmt->renameType == OBJECT_INDEX;
4122  Oid relid;
4123  ObjectAddress address;
4124 
4125  /*
4126  * Grab an exclusive lock on the target table, index, sequence, view,
4127  * materialized view, or foreign table, which we will NOT release until
4128  * end of transaction.
4129  *
4130  * Lock level used here should match RenameRelationInternal, to avoid lock
4131  * escalation. However, because ALTER INDEX can be used with any relation
4132  * type, we mustn't believe without verification.
4133  */
4134  for (;;)
4135  {
4136  LOCKMODE lockmode;
4137  char relkind;
4138  bool obj_is_index;
4139 
4140  lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
4141 
4142  relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
4143  stmt->missing_ok ? RVR_MISSING_OK : 0,
4145  (void *) stmt);
4146 
4147  if (!OidIsValid(relid))
4148  {
4149  ereport(NOTICE,
4150  (errmsg("relation \"%s\" does not exist, skipping",
4151  stmt->relation->relname)));
4152  return InvalidObjectAddress;
4153  }
4154 
4155  /*
4156  * We allow mismatched statement and object types (e.g., ALTER INDEX
4157  * to rename a table), but we might've used the wrong lock level. If
4158  * that happens, retry with the correct lock level. We don't bother
4159  * if we already acquired AccessExclusiveLock with an index, however.
4160  */
4161  relkind = get_rel_relkind(relid);
4162  obj_is_index = (relkind == RELKIND_INDEX ||
4163  relkind == RELKIND_PARTITIONED_INDEX);
4164  if (obj_is_index || is_index_stmt == obj_is_index)
4165  break;
4166 
4167  UnlockRelationOid(relid, lockmode);
4168  is_index_stmt = obj_is_index;
4169  }
4170 
4171  /* Do the work */
4172  RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
4173 
4174  ObjectAddressSet(address, RelationRelationId, relid);
4175 
4176  return address;
4177 }
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:226
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:4183

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

4184 {
4185  Relation targetrelation;
4186  Relation relrelation; /* for RELATION relation */
4187  ItemPointerData otid;
4188  HeapTuple reltup;
4189  Form_pg_class relform;
4190  Oid namespaceId;
4191 
4192  /*
4193  * Grab a lock on the target relation, which we will NOT release until end
4194  * of transaction. We need at least a self-exclusive lock so that
4195  * concurrent DDL doesn't overwrite the rename if they start updating
4196  * while still seeing the old version. The lock also guards against
4197  * triggering relcache reloads in concurrent sessions, which might not
4198  * handle this information changing under them. For indexes, we can use a
4199  * reduced lock level because RelationReloadIndexInfo() handles indexes
4200  * specially.
4201  */
4202  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
4203  namespaceId = RelationGetNamespace(targetrelation);
4204 
4205  /*
4206  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
4207  */
4208  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4209 
4210  reltup = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(myrelid));
4211  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4212  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4213  otid = reltup->t_self;
4214  relform = (Form_pg_class) GETSTRUCT(reltup);
4215 
4216  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
4217  ereport(ERROR,
4218  (errcode(ERRCODE_DUPLICATE_TABLE),
4219  errmsg("relation \"%s\" already exists",
4220  newrelname)));
4221 
4222  /*
4223  * RenameRelation is careful not to believe the caller's idea of the
4224  * relation kind being handled. We don't have to worry about this, but
4225  * let's not be totally oblivious to it. We can process an index as
4226  * not-an-index, but not the other way around.
4227  */
4228  Assert(!is_index ||
4229  is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4230  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
4231 
4232  /*
4233  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
4234  * because it's a copy...)
4235  */
4236  namestrcpy(&(relform->relname), newrelname);
4237 
4238  CatalogTupleUpdate(relrelation, &otid, reltup);
4239  UnlockTuple(relrelation, &otid, InplaceUpdateTupleLock);
4240 
4241  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
4242  InvalidOid, is_internal);
4243 
4244  heap_freetuple(reltup);
4245  table_close(relrelation, RowExclusiveLock);
4246 
4247  /*
4248  * Also rename the associated type, if any.
4249  */
4250  if (OidIsValid(targetrelation->rd_rel->reltype))
4251  RenameTypeInternal(targetrelation->rd_rel->reltype,
4252  newrelname, namespaceId);
4253 
4254  /*
4255  * Also rename the associated constraint, if any.
4256  */
4257  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
4258  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
4259  {
4260  Oid constraintId = get_index_constraint(myrelid);
4261 
4262  if (OidIsValid(constraintId))
4263  RenameConstraintById(constraintId, newrelname);
4264  }
4265 
4266  /*
4267  * Close rel, but keep lock!
4268  */
4269  relation_close(targetrelation, NoLock);
4270 }
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 4276 of file tablecmds.c.

4277 {
4278  Relation relrelation; /* for RELATION relation */
4279  HeapTuple reltup;
4280  Form_pg_class relform;
4281 
4282  /*
4283  * Find relation's pg_class tuple.
4284  */
4285  relrelation = table_open(RelationRelationId, RowExclusiveLock);
4286 
4287  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
4288  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
4289  elog(ERROR, "cache lookup failed for relation %u", myrelid);
4290  relform = (Form_pg_class) GETSTRUCT(reltup);
4291 
4292  /*
4293  * Update pg_class tuple.
4294  */
4295  relform->relrewrite = InvalidOid;
4296 
4297  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
4298 
4299  heap_freetuple(reltup);
4300  table_close(relrelation, RowExclusiveLock);
4301 }
#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 3560 of file tablecmds.c.

3561 {
3562  Relation relationRelation;
3563  HeapTuple tuple;
3564  Form_pg_class classtuple;
3565 
3567  ShareUpdateExclusiveLock, false) ||
3568  CheckRelationOidLockedByMe(relationId,
3569  ShareRowExclusiveLock, true));
3570 
3571  /*
3572  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3573  */
3574  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3575  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3576  if (!HeapTupleIsValid(tuple))
3577  elog(ERROR, "cache lookup failed for relation %u", relationId);
3578  classtuple = (Form_pg_class) GETSTRUCT(tuple);
3579 
3580  if (classtuple->relhassubclass != relhassubclass)
3581  {
3582  classtuple->relhassubclass = relhassubclass;
3583  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3584  }
3585  else
3586  {
3587  /* no need to change tuple, but force relcache rebuild anyway */
3589  }
3590 
3591  heap_freetuple(tuple);
3592  table_close(relationRelation, RowExclusiveLock);
3593 }
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1587
bool CheckRelationOidLockedByMe(Oid relid, LOCKMODE lockmode, bool orstronger)
Definition: lmgr.c:346

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

3666 {
3667  Relation pg_class;
3668  HeapTuple tuple;
3669  ItemPointerData otid;
3670  Form_pg_class rd_rel;
3671  Oid reloid = RelationGetRelid(rel);
3672 
3673  Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3674 
3675  /* Get a modifiable copy of the relation's pg_class row. */
3676  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3677 
3678  tuple = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(reloid));
3679  if (!HeapTupleIsValid(tuple))
3680  elog(ERROR, "cache lookup failed for relation %u", reloid);
3681  otid = tuple->t_self;
3682  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3683 
3684  /* Update the pg_class row. */
3685  rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3686  InvalidOid : newTableSpaceId;
3687  if (RelFileNumberIsValid(newRelFilenumber))
3688  rd_rel->relfilenode = newRelFilenumber;
3689  CatalogTupleUpdate(pg_class, &otid, tuple);
3690  UnlockTuple(pg_class, &otid, InplaceUpdateTupleLock);
3691 
3692  /*
3693  * Record dependency on tablespace. This is only required for relations
3694  * that have no physical storage.
3695  */
3696  if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3697  changeDependencyOnTablespace(RelationRelationId, reloid,
3698  rd_rel->reltablespace);
3699 
3700  heap_freetuple(tuple);
3701  table_close(pg_class, RowExclusiveLock);
3702 }
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:3606

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