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

Go to the source code of this file.

Functions

ObjectAddress DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
 
void RemoveRelations (DropStmt *drop)
 
Oid AlterTableLookupRelation (AlterTableStmt *stmt, LOCKMODE lockmode)
 
void AlterTable (Oid relid, LOCKMODE lockmode, AlterTableStmt *stmt)
 
LOCKMODE AlterTableGetLockLevel (List *cmds)
 
void ATExecChangeOwner (Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
 
void AlterTableInternal (Oid relid, List *cmds, bool recurse)
 
Oid AlterTableMoveAll (AlterTableMoveAllStmt *stmt)
 
ObjectAddress AlterTableNamespace (AlterObjectSchemaStmt *stmt, Oid *oldschema)
 
void AlterTableNamespaceInternal (Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
 
void AlterRelationNamespaceInternal (Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
 
void CheckTableNotInUse (Relation rel, const char *stmt)
 
void ExecuteTruncate (TruncateStmt *stmt)
 
void SetRelationHasSubclass (Oid relationId, bool relhassubclass)
 
ObjectAddress renameatt (RenameStmt *stmt)
 
ObjectAddress renameatt_type (RenameStmt *stmt)
 
ObjectAddress RenameConstraint (RenameStmt *stmt)
 
ObjectAddress RenameRelation (RenameStmt *stmt)
 
void RenameRelationInternal (Oid myrelid, const char *newrelname, bool is_internal)
 
void find_composite_type_dependencies (Oid typeOid, Relation origRelation, const char *origTypeName)
 
void check_of_type (HeapTuple typetuple)
 
void register_on_commit_action (Oid relid, OnCommitAction action)
 
void remove_on_commit_action (Oid relid)
 
void PreCommit_on_commit_actions (void)
 
void AtEOXact_on_commit_actions (bool isCommit)
 
void AtEOSubXact_on_commit_actions (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
void RangeVarCallbackOwnsTable (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
void RangeVarCallbackOwnsRelation (const RangeVar *relation, Oid relId, Oid oldRelId, void *noCatalogs)
 
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 12757 of file tablecmds.c.

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

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

12761 {
12762  HeapTuple classTup;
12763  Form_pg_class classForm;
12764  ObjectAddress thisobj;
12765  bool already_done = false;
12766 
12767  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
12768  if (!HeapTupleIsValid(classTup))
12769  elog(ERROR, "cache lookup failed for relation %u", relOid);
12770  classForm = (Form_pg_class) GETSTRUCT(classTup);
12771 
12772  Assert(classForm->relnamespace == oldNspOid);
12773 
12774  thisobj.classId = RelationRelationId;
12775  thisobj.objectId = relOid;
12776  thisobj.objectSubId = 0;
12777 
12778  /*
12779  * If the object has already been moved, don't move it again. If it's
12780  * already in the right place, don't move it, but still fire the object
12781  * access hook.
12782  */
12783  already_done = object_address_present(&thisobj, objsMoved);
12784  if (!already_done && oldNspOid != newNspOid)
12785  {
12786  /* check for duplicate name (more friendly than unique-index failure) */
12787  if (get_relname_relid(NameStr(classForm->relname),
12788  newNspOid) != InvalidOid)
12789  ereport(ERROR,
12790  (errcode(ERRCODE_DUPLICATE_TABLE),
12791  errmsg("relation \"%s\" already exists in schema \"%s\"",
12792  NameStr(classForm->relname),
12793  get_namespace_name(newNspOid))));
12794 
12795  /* classTup is a copy, so OK to scribble on */
12796  classForm->relnamespace = newNspOid;
12797 
12798  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
12799 
12800  /* Update dependency on schema if caller said so */
12801  if (hasDependEntry &&
12803  relOid,
12805  oldNspOid,
12806  newNspOid) != 1)
12807  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
12808  NameStr(classForm->relname));
12809  }
12810  if (!already_done)
12811  {
12812  add_exact_object_address(&thisobj, objsMoved);
12813 
12815  }
12816 
12817  heap_freetuple(classTup);
12818 }
#define NamespaceRelationId
Definition: pg_namespace.h:34
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define RelationRelationId
Definition: pg_class.h:29
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2248
int errcode(int sqlerrcode)
Definition: elog.c:575
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2188
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1687
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:688
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
int errmsg(const char *fmt,...)
Definition: elog.c:797
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:295
#define NameStr(name)
Definition: c.h:565
#define elog
Definition: elog.h:219

◆ AlterTable()

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

Definition at line 3195 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3196 {
3197  Relation rel;
3198 
3199  /* Caller is required to provide an adequate lock. */
3200  rel = relation_open(relid, NoLock);
3201 
3202  CheckTableNotInUse(rel, "ALTER TABLE");
3203 
3204  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode);
3205 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3513
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3115
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1715
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 3264 of file tablecmds.c.

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

Referenced by AlterTableInternal(), and ProcessUtilitySlow().

3265 {
3266  /*
3267  * This only works if we read catalog tables using MVCC snapshots.
3268  */
3269  ListCell *lcmd;
3271 
3272  foreach(lcmd, cmds)
3273  {
3274  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3275  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
3276 
3277  switch (cmd->subtype)
3278  {
3279  /*
3280  * These subcommands rewrite the heap, so require full locks.
3281  */
3282  case AT_AddColumn: /* may rewrite heap, in some cases and visible
3283  * to SELECT */
3284  case AT_SetTableSpace: /* must rewrite heap */
3285  case AT_AlterColumnType: /* must rewrite heap */
3286  case AT_AddOids: /* must rewrite heap */
3287  cmd_lockmode = AccessExclusiveLock;
3288  break;
3289 
3290  /*
3291  * These subcommands may require addition of toast tables. If
3292  * we add a toast table to a table currently being scanned, we
3293  * might miss data added to the new toast table by concurrent
3294  * insert transactions.
3295  */
3296  case AT_SetStorage: /* may add toast tables, see
3297  * ATRewriteCatalogs() */
3298  cmd_lockmode = AccessExclusiveLock;
3299  break;
3300 
3301  /*
3302  * Removing constraints can affect SELECTs that have been
3303  * optimised assuming the constraint holds true.
3304  */
3305  case AT_DropConstraint: /* as DROP INDEX */
3306  case AT_DropNotNull: /* may change some SQL plans */
3307  cmd_lockmode = AccessExclusiveLock;
3308  break;
3309 
3310  /*
3311  * Subcommands that may be visible to concurrent SELECTs
3312  */
3313  case AT_DropColumn: /* change visible to SELECT */
3314  case AT_AddColumnToView: /* CREATE VIEW */
3315  case AT_DropOids: /* calls AT_DropColumn */
3316  case AT_EnableAlwaysRule: /* may change SELECT rules */
3317  case AT_EnableReplicaRule: /* may change SELECT rules */
3318  case AT_EnableRule: /* may change SELECT rules */
3319  case AT_DisableRule: /* may change SELECT rules */
3320  cmd_lockmode = AccessExclusiveLock;
3321  break;
3322 
3323  /*
3324  * Changing owner may remove implicit SELECT privileges
3325  */
3326  case AT_ChangeOwner: /* change visible to SELECT */
3327  cmd_lockmode = AccessExclusiveLock;
3328  break;
3329 
3330  /*
3331  * Changing foreign table options may affect optimization.
3332  */
3333  case AT_GenericOptions:
3335  cmd_lockmode = AccessExclusiveLock;
3336  break;
3337 
3338  /*
3339  * These subcommands affect write operations only.
3340  */
3341  case AT_EnableTrig:
3342  case AT_EnableAlwaysTrig:
3343  case AT_EnableReplicaTrig:
3344  case AT_EnableTrigAll:
3345  case AT_EnableTrigUser:
3346  case AT_DisableTrig:
3347  case AT_DisableTrigAll:
3348  case AT_DisableTrigUser:
3349  cmd_lockmode = ShareRowExclusiveLock;
3350  break;
3351 
3352  /*
3353  * These subcommands affect write operations only. XXX
3354  * Theoretically, these could be ShareRowExclusiveLock.
3355  */
3356  case AT_ColumnDefault:
3357  case AT_AlterConstraint:
3358  case AT_AddIndex: /* from ADD CONSTRAINT */
3359  case AT_AddIndexConstraint:
3360  case AT_ReplicaIdentity:
3361  case AT_SetNotNull:
3362  case AT_EnableRowSecurity:
3363  case AT_DisableRowSecurity:
3364  case AT_ForceRowSecurity:
3365  case AT_NoForceRowSecurity:
3366  case AT_AddIdentity:
3367  case AT_DropIdentity:
3368  case AT_SetIdentity:
3369  cmd_lockmode = AccessExclusiveLock;
3370  break;
3371 
3372  case AT_AddConstraint:
3373  case AT_ProcessedConstraint: /* becomes AT_AddConstraint */
3374  case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
3375  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
3376  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
3377  if (IsA(cmd->def, Constraint))
3378  {
3379  Constraint *con = (Constraint *) cmd->def;
3380 
3381  switch (con->contype)
3382  {
3383  case CONSTR_EXCLUSION:
3384  case CONSTR_PRIMARY:
3385  case CONSTR_UNIQUE:
3386 
3387  /*
3388  * Cases essentially the same as CREATE INDEX. We
3389  * could reduce the lock strength to ShareLock if
3390  * we can work out how to allow concurrent catalog
3391  * updates. XXX Might be set down to
3392  * ShareRowExclusiveLock but requires further
3393  * analysis.
3394  */
3395  cmd_lockmode = AccessExclusiveLock;
3396  break;
3397  case CONSTR_FOREIGN:
3398 
3399  /*
3400  * We add triggers to both tables when we add a
3401  * Foreign Key, so the lock level must be at least
3402  * as strong as CREATE TRIGGER.
3403  */
3404  cmd_lockmode = ShareRowExclusiveLock;
3405  break;
3406 
3407  default:
3408  cmd_lockmode = AccessExclusiveLock;
3409  }
3410  }
3411  break;
3412 
3413  /*
3414  * These subcommands affect inheritance behaviour. Queries
3415  * started before us will continue to see the old inheritance
3416  * behaviour, while queries started after we commit will see
3417  * new behaviour. No need to prevent reads or writes to the
3418  * subtable while we hook it up though. Changing the TupDesc
3419  * may be a problem, so keep highest lock.
3420  */
3421  case AT_AddInherit:
3422  case AT_DropInherit:
3423  cmd_lockmode = AccessExclusiveLock;
3424  break;
3425 
3426  /*
3427  * These subcommands affect implicit row type conversion. They
3428  * have affects similar to CREATE/DROP CAST on queries. don't
3429  * provide for invalidating parse trees as a result of such
3430  * changes, so we keep these at AccessExclusiveLock.
3431  */
3432  case AT_AddOf:
3433  case AT_DropOf:
3434  cmd_lockmode = AccessExclusiveLock;
3435  break;
3436 
3437  /*
3438  * Only used by CREATE OR REPLACE VIEW which must conflict
3439  * with an SELECTs currently using the view.
3440  */
3441  case AT_ReplaceRelOptions:
3442  cmd_lockmode = AccessExclusiveLock;
3443  break;
3444 
3445  /*
3446  * These subcommands affect general strategies for performance
3447  * and maintenance, though don't change the semantic results
3448  * from normal data reads and writes. Delaying an ALTER TABLE
3449  * behind currently active writes only delays the point where
3450  * the new strategy begins to take effect, so there is no
3451  * benefit in waiting. In this case the minimum restriction
3452  * applies: we don't currently allow concurrent catalog
3453  * updates.
3454  */
3455  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
3456  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
3457  case AT_DropCluster: /* Uses MVCC in getIndexes() */
3458  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
3459  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
3460  cmd_lockmode = ShareUpdateExclusiveLock;
3461  break;
3462 
3463  case AT_SetLogged:
3464  case AT_SetUnLogged:
3465  cmd_lockmode = AccessExclusiveLock;
3466  break;
3467 
3468  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
3469  cmd_lockmode = ShareUpdateExclusiveLock;
3470  break;
3471 
3472  /*
3473  * Rel options are more complex than first appears. Options
3474  * are set here for tables, views and indexes; for historical
3475  * reasons these can all be used with ALTER TABLE, so we can't
3476  * decide between them using the basic grammar.
3477  */
3478  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
3479  * getTables() */
3480  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
3481  * getTables() */
3482  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
3483  break;
3484 
3485  case AT_AttachPartition:
3486  case AT_DetachPartition:
3487  cmd_lockmode = AccessExclusiveLock;
3488  break;
3489 
3490  default: /* oops */
3491  elog(ERROR, "unrecognized alter table type: %d",
3492  (int) cmd->subtype);
3493  break;
3494  }
3495 
3496  /*
3497  * Take the greatest lockmode from any subcommand
3498  */
3499  if (cmd_lockmode > lockmode)
3500  lockmode = cmd_lockmode;
3501  }
3502 
3503  return lockmode;
3504 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:564
int LOCKMODE
Definition: lockdefs.h:26
AlterTableType subtype
Definition: parsenodes.h:1803
#define ERROR
Definition: elog.h:43
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define lfirst(lc)
Definition: pg_list.h:106
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:1539
#define AccessExclusiveLock
Definition: lockdefs.h:45
ConstrType contype
Definition: parsenodes.h:2089
#define elog
Definition: elog.h:219
Definition: pg_list.h:45

◆ AlterTableInternal()

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

Definition at line 3219 of file tablecmds.c.

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

Referenced by AlterTableMoveAll(), DefineVirtualRelation(), and index_check_primary_key().

3220 {
3221  Relation rel;
3222  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
3223 
3224  rel = relation_open(relid, lockmode);
3225 
3227 
3228  ATController(NULL, rel, cmds, recurse, lockmode);
3229 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3513
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:3264
void EventTriggerAlterTableRelid(Oid objectId)
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3145 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3146 {
3147  return RangeVarGetRelidExtended(stmt->relation, lockmode, stmt->missing_ok, false,
3149  (void *) stmt);
3150 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:218
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:13234
RangeVar * relation
Definition: parsenodes.h:1715

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 10861 of file tablecmds.c.

References AccessExclusiveLock, AccessShareLock, ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTableInternal(), Anum_pg_class_reltablespace, 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(), GLOBALTABLESPACE_OID, heap_beginscan_catalog(), heap_close, heap_endscan(), heap_getnext(), heap_open(), HeapTupleGetOid, InvalidOid, isAnyTempNamespace(), IsSystemNamespace(), lappend(), lappend_oid(), lfirst_oid, list_member_oid(), LockRelationOid(), makeNode, MyDatabaseTableSpace, AlterTableCmd::name, NameStr, AlterTableMoveAllStmt::new_tablespacename, NIL, NOTICE, AlterTableMoveAllStmt::nowait, OBJECT_INDEX, OBJECT_MATVIEW, OBJECT_TABLE, OBJECT_TABLESPACE, ObjectIdGetDatum, AlterTableMoveAllStmt::objtype, OidIsValid, AlterTableMoveAllStmt::orig_tablespacename, pg_class_ownercheck(), pg_tablespace_aclcheck(), PG_TOAST_NAMESPACE, RelationRelationId, RELKIND_INDEX, RELKIND_MATVIEW, RELKIND_PARTITIONED_INDEX, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, AlterTableMoveAllStmt::roles, roleSpecsToIds(), ScanKeyInit(), and AlterTableCmd::subtype.

Referenced by ProcessUtilitySlow().

10862 {
10863  List *relations = NIL;
10864  ListCell *l;
10865  ScanKeyData key[1];
10866  Relation rel;
10867  HeapScanDesc scan;
10868  HeapTuple tuple;
10869  Oid orig_tablespaceoid;
10870  Oid new_tablespaceoid;
10871  List *role_oids = roleSpecsToIds(stmt->roles);
10872 
10873  /* Ensure we were not asked to move something we can't */
10874  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
10875  stmt->objtype != OBJECT_MATVIEW)
10876  ereport(ERROR,
10877  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
10878  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
10879 
10880  /* Get the orig and new tablespace OIDs */
10881  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
10882  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
10883 
10884  /* Can't move shared relations in to or out of pg_global */
10885  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
10886  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
10887  new_tablespaceoid == GLOBALTABLESPACE_OID)
10888  ereport(ERROR,
10889  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
10890  errmsg("cannot move relations in to or out of pg_global tablespace")));
10891 
10892  /*
10893  * Must have CREATE rights on the new tablespace, unless it is the
10894  * database default tablespace (which all users implicitly have CREATE
10895  * rights on).
10896  */
10897  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
10898  {
10899  AclResult aclresult;
10900 
10901  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
10902  ACL_CREATE);
10903  if (aclresult != ACLCHECK_OK)
10904  aclcheck_error(aclresult, OBJECT_TABLESPACE,
10905  get_tablespace_name(new_tablespaceoid));
10906  }
10907 
10908  /*
10909  * Now that the checks are done, check if we should set either to
10910  * InvalidOid because it is our database's default tablespace.
10911  */
10912  if (orig_tablespaceoid == MyDatabaseTableSpace)
10913  orig_tablespaceoid = InvalidOid;
10914 
10915  if (new_tablespaceoid == MyDatabaseTableSpace)
10916  new_tablespaceoid = InvalidOid;
10917 
10918  /* no-op */
10919  if (orig_tablespaceoid == new_tablespaceoid)
10920  return new_tablespaceoid;
10921 
10922  /*
10923  * Walk the list of objects in the tablespace and move them. This will
10924  * only find objects in our database, of course.
10925  */
10926  ScanKeyInit(&key[0],
10928  BTEqualStrategyNumber, F_OIDEQ,
10929  ObjectIdGetDatum(orig_tablespaceoid));
10930 
10932  scan = heap_beginscan_catalog(rel, 1, key);
10933  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
10934  {
10935  Oid relOid = HeapTupleGetOid(tuple);
10936  Form_pg_class relForm;
10937 
10938  relForm = (Form_pg_class) GETSTRUCT(tuple);
10939 
10940  /*
10941  * Do not move objects in pg_catalog as part of this, if an admin
10942  * really wishes to do so, they can issue the individual ALTER
10943  * commands directly.
10944  *
10945  * Also, explicitly avoid any shared tables, temp tables, or TOAST
10946  * (TOAST will be moved with the main table).
10947  */
10948  if (IsSystemNamespace(relForm->relnamespace) || relForm->relisshared ||
10949  isAnyTempNamespace(relForm->relnamespace) ||
10950  relForm->relnamespace == PG_TOAST_NAMESPACE)
10951  continue;
10952 
10953  /* Only move the object type requested */
10954  if ((stmt->objtype == OBJECT_TABLE &&
10955  relForm->relkind != RELKIND_RELATION &&
10956  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
10957  (stmt->objtype == OBJECT_INDEX &&
10958  relForm->relkind != RELKIND_INDEX &&
10959  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
10960  (stmt->objtype == OBJECT_MATVIEW &&
10961  relForm->relkind != RELKIND_MATVIEW))
10962  continue;
10963 
10964  /* Check if we are only moving objects owned by certain roles */
10965  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
10966  continue;
10967 
10968  /*
10969  * Handle permissions-checking here since we are locking the tables
10970  * and also to avoid doing a bunch of work only to fail part-way. Note
10971  * that permissions will also be checked by AlterTableInternal().
10972  *
10973  * Caller must be considered an owner on the table to move it.
10974  */
10975  if (!pg_class_ownercheck(relOid, GetUserId()))
10977  NameStr(relForm->relname));
10978 
10979  if (stmt->nowait &&
10981  ereport(ERROR,
10982  (errcode(ERRCODE_OBJECT_IN_USE),
10983  errmsg("aborting because lock on relation \"%s.%s\" is not available",
10984  get_namespace_name(relForm->relnamespace),
10985  NameStr(relForm->relname))));
10986  else
10988 
10989  /* Add to our list of objects to move */
10990  relations = lappend_oid(relations, relOid);
10991  }
10992 
10993  heap_endscan(scan);
10995 
10996  if (relations == NIL)
10997  ereport(NOTICE,
10998  (errcode(ERRCODE_NO_DATA_FOUND),
10999  errmsg("no matching relations in tablespace \"%s\" found",
11000  orig_tablespaceoid == InvalidOid ? "(database default)" :
11001  get_tablespace_name(orig_tablespaceoid))));
11002 
11003  /* Everything is locked, loop through and move all of the relations. */
11004  foreach(l, relations)
11005  {
11006  List *cmds = NIL;
11008 
11009  cmd->subtype = AT_SetTableSpace;
11010  cmd->name = stmt->new_tablespacename;
11011 
11012  cmds = lappend(cmds, cmd);
11013 
11015  /* OID is set by AlterTableInternal */
11016  AlterTableInternal(lfirst_oid(l), cmds, false);
11018  }
11019 
11020  return new_tablespaceoid;
11021 }
#define NIL
Definition: pg_list.h:69
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:138
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1380
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4702
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1568
Oid GetUserId(void)
Definition: miscinit.c:284
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
#define RelationRelationId
Definition: pg_class.h:29
#define Anum_pg_class_reltablespace
Definition: pg_class.h:110
#define RELKIND_MATVIEW
Definition: pg_class.h:165
#define AccessShareLock
Definition: lockdefs.h:36
#define GLOBALTABLESPACE_OID
Definition: pg_tablespace.h:64
Definition: nodes.h:513
int errcode(int sqlerrcode)
Definition: elog.c:575
AlterTableType subtype
Definition: parsenodes.h:1803
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
#define PG_TOAST_NAMESPACE
Definition: pg_namespace.h:74
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:594
Oid MyDatabaseTableSpace
Definition: globals.c:79
void EventTriggerAlterTableStart(Node *parsetree)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:82
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
HeapScanDesc heap_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
Definition: heapam.c:1408
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
#define RELKIND_PARTITIONED_INDEX
Definition: pg_class.h:169
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
AclResult
Definition: acl.h:178
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1831
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
bool IsSystemNamespace(Oid namespaceId)
Definition: catalog.c:163
#define InvalidOid
Definition: postgres_ext.h:36
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:561
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1396
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4752
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:3219
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1426
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:565
#define RELKIND_INDEX
Definition: pg_class.h:161
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3156
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:700
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
#define RELKIND_RELATION
Definition: pg_class.h:160
Definition: pg_list.h:45
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:108
void EventTriggerAlterTableEnd(void)

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 12648 of file tablecmds.c.

References AccessExclusiveLock, AlterTableNamespaceInternal(), CheckSetNamespace(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, ereport, errcode(), errdetail(), errmsg(), ERROR, free_object_addresses(), get_rel_name(), InvalidObjectAddress, makeRangeVar(), AlterObjectSchemaStmt::missing_ok, new_object_addresses(), NoLock, NOTICE, ObjectAddressSet, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelidExtended(), RelationData::rd_rel, AlterObjectSchemaStmt::relation, relation_close(), relation_open(), RelationGetNamespace, RelationGetRelationName, RelationRelationId, OnCommitItem::relid, RELKIND_SEQUENCE, and sequenceIsOwned().

Referenced by ExecAlterObjectSchemaStmt().

12649 {
12650  Relation rel;
12651  Oid relid;
12652  Oid oldNspOid;
12653  Oid nspOid;
12654  RangeVar *newrv;
12655  ObjectAddresses *objsMoved;
12656  ObjectAddress myself;
12657 
12659  stmt->missing_ok, false,
12661  (void *) stmt);
12662 
12663  if (!OidIsValid(relid))
12664  {
12665  ereport(NOTICE,
12666  (errmsg("relation \"%s\" does not exist, skipping",
12667  stmt->relation->relname)));
12668  return InvalidObjectAddress;
12669  }
12670 
12671  rel = relation_open(relid, NoLock);
12672 
12673  oldNspOid = RelationGetNamespace(rel);
12674 
12675  /* If it's an owned sequence, disallow moving it by itself. */
12676  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
12677  {
12678  Oid tableId;
12679  int32 colId;
12680 
12681  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
12682  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
12683  ereport(ERROR,
12684  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12685  errmsg("cannot move an owned sequence into another schema"),
12686  errdetail("Sequence \"%s\" is linked to table \"%s\".",
12688  get_rel_name(tableId))));
12689  }
12690 
12691  /* Get and lock schema OID and check its permissions. */
12692  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
12693  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
12694 
12695  /* common checks on switching namespaces */
12696  CheckSetNamespace(oldNspOid, nspOid);
12697 
12698  objsMoved = new_object_addresses();
12699  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
12700  free_object_addresses(objsMoved);
12701 
12702  ObjectAddressSet(myself, RelationRelationId, relid);
12703 
12704  if (oldschema)
12705  *oldschema = oldNspOid;
12706 
12707  /* close rel, but keep lock until commit */
12708  relation_close(rel, NoLock);
12709 
12710  return myself;
12711 }
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:500
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:218
#define RelationRelationId
Definition: pg_class.h:29
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2133
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2404
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:594
signed int int32
Definition: c.h:302
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:43
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12719
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:13234
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define RelationGetRelationName(relation)
Definition: rel.h:445
#define ereport(elevel, rest)
Definition: elog.h:122
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2928
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:508
#define NOTICE
Definition: elog.h:37
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120
#define RELKIND_SEQUENCE
Definition: pg_class.h:162
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:421
#define RelationGetNamespace(relation)
Definition: rel.h:452

◆ AlterTableNamespaceInternal()

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

Definition at line 12719 of file tablecmds.c.

References AccessExclusiveLock, AlterConstraintNamespaces(), AlterIndexNamespaces(), AlterRelationNamespaceInternal(), AlterSeqNamespaces(), AlterTypeNamespaceInternal(), Assert, heap_close, heap_open(), RelationData::rd_rel, RelationGetRelid, RelationRelationId, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, and RowExclusiveLock.

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

12721 {
12722  Relation classRel;
12723 
12724  Assert(objsMoved != NULL);
12725 
12726  /* OK, modify the pg_class row and pg_depend entry */
12728 
12729  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
12730  nspOid, true, objsMoved);
12731 
12732  /* Fix the table's row type too */
12733  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
12734  nspOid, false, false, objsMoved);
12735 
12736  /* Fix other dependent stuff */
12737  if (rel->rd_rel->relkind == RELKIND_RELATION ||
12738  rel->rd_rel->relkind == RELKIND_MATVIEW ||
12739  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12740  {
12741  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
12742  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
12743  objsMoved, AccessExclusiveLock);
12744  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
12745  false, objsMoved);
12746  }
12747 
12748  heap_close(classRel, RowExclusiveLock);
12749 }
#define RelationRelationId
Definition: pg_class.h:29
#define RELKIND_MATVIEW
Definition: pg_class.h:165
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3580
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12827
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:12872
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define Assert(condition)
Definition: c.h:688
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12757
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RelationGetRelid(relation)
Definition: rel.h:425

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 13124 of file tablecmds.c.

References OnCommitItem::creating_subid, OnCommitItem::deleting_subid, InvalidSubTransactionId, lfirst, list_delete_cell(), list_head(), lnext, and pfree().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

13126 {
13127  ListCell *cur_item;
13128  ListCell *prev_item;
13129 
13130  prev_item = NULL;
13131  cur_item = list_head(on_commits);
13132 
13133  while (cur_item != NULL)
13134  {
13135  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
13136 
13137  if (!isCommit && oc->creating_subid == mySubid)
13138  {
13139  /* cur_item must be removed */
13140  on_commits = list_delete_cell(on_commits, cur_item, prev_item);
13141  pfree(oc);
13142  if (prev_item)
13143  cur_item = lnext(prev_item);
13144  else
13145  cur_item = list_head(on_commits);
13146  }
13147  else
13148  {
13149  /* cur_item must be preserved */
13150  if (oc->creating_subid == mySubid)
13151  oc->creating_subid = parentSubid;
13152  if (oc->deleting_subid == mySubid)
13153  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
13154  prev_item = cur_item;
13155  cur_item = lnext(prev_item);
13156  }
13157  }
13158 }
SubTransactionId creating_subid
Definition: tablecmds.c:120
void pfree(void *pointer)
Definition: mcxt.c:936
static List * on_commits
Definition: tablecmds.c:124
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
List * list_delete_cell(List *list, ListCell *cell, ListCell *prev)
Definition: list.c:528
SubTransactionId deleting_subid
Definition: tablecmds.c:121
#define lfirst(lc)
Definition: pg_list.h:106
#define InvalidSubTransactionId
Definition: c.h:469

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 13082 of file tablecmds.c.

References OnCommitItem::creating_subid, OnCommitItem::deleting_subid, InvalidSubTransactionId, lfirst, list_delete_cell(), list_head(), lnext, and pfree().

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

13083 {
13084  ListCell *cur_item;
13085  ListCell *prev_item;
13086 
13087  prev_item = NULL;
13088  cur_item = list_head(on_commits);
13089 
13090  while (cur_item != NULL)
13091  {
13092  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
13093 
13094  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
13096  {
13097  /* cur_item must be removed */
13098  on_commits = list_delete_cell(on_commits, cur_item, prev_item);
13099  pfree(oc);
13100  if (prev_item)
13101  cur_item = lnext(prev_item);
13102  else
13103  cur_item = list_head(on_commits);
13104  }
13105  else
13106  {
13107  /* cur_item must be preserved */
13110  prev_item = cur_item;
13111  cur_item = lnext(prev_item);
13112  }
13113  }
13114 }
SubTransactionId creating_subid
Definition: tablecmds.c:120
void pfree(void *pointer)
Definition: mcxt.c:936
static List * on_commits
Definition: tablecmds.c:124
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
List * list_delete_cell(List *list, ListCell *cell, ListCell *prev)
Definition: list.c:528
SubTransactionId deleting_subid
Definition: tablecmds.c:121
#define lfirst(lc)
Definition: pg_list.h:106
#define InvalidSubTransactionId
Definition: c.h:469

◆ ATExecChangeOwner()

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

Definition at line 10037 of file tablecmds.c.

References ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, aclnewowner(), AlterTypeOwnerInternal(), Anum_pg_class_relacl, Anum_pg_class_relowner, ATExecChangeOwner(), CatalogTupleUpdate(), change_owner_fix_column_acls(), change_owner_recurse_to_sequences(), changeDependencyOnOwner(), check_is_member_of_role(), DatumGetAclP, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, elog, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, get_namespace_name(), get_rel_name(), get_rel_relkind(), get_relkind_objtype(), GETSTRUCT, GetUserId(), heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleIsValid, i, InvalidOid, InvokeObjectPostAlterHook, lfirst_oid, list_free(), NameStr, Natts_pg_class, NoLock, OBJECT_SCHEMA, ObjectIdGetDatum, pg_class_ownercheck(), pg_namespace_aclcheck(), PointerGetDatum, relation_close(), relation_open(), RelationGetDescr, RelationGetIndexList(), RelationGetRelationName, RelationRelationId, ReleaseSysCache(), RELKIND_COMPOSITE_TYPE, RELKIND_FOREIGN_TABLE, RELKIND_INDEX, RELKIND_MATVIEW, RELKIND_PARTITIONED_INDEX, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_TOASTVALUE, RELKIND_VIEW, RELOID, RowExclusiveLock, SearchSysCache1(), sequenceIsOwned(), superuser(), SysCacheGetAttr(), HeapTupleData::t_self, and WARNING.

Referenced by AlterTypeOwner_oid(), ATExecChangeOwner(), ATExecCmd(), change_owner_recurse_to_sequences(), and shdepReassignOwned().

10038 {
10039  Relation target_rel;
10040  Relation class_rel;
10041  HeapTuple tuple;
10042  Form_pg_class tuple_class;
10043 
10044  /*
10045  * Get exclusive lock till end of transaction on the target table. Use
10046  * relation_open so that we can work on indexes and sequences.
10047  */
10048  target_rel = relation_open(relationOid, lockmode);
10049 
10050  /* Get its pg_class tuple, too */
10052 
10053  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
10054  if (!HeapTupleIsValid(tuple))
10055  elog(ERROR, "cache lookup failed for relation %u", relationOid);
10056  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
10057 
10058  /* Can we change the ownership of this tuple? */
10059  switch (tuple_class->relkind)
10060  {
10061  case RELKIND_RELATION:
10062  case RELKIND_VIEW:
10063  case RELKIND_MATVIEW:
10064  case RELKIND_FOREIGN_TABLE:
10066  /* ok to change owner */
10067  break;
10068  case RELKIND_INDEX:
10069  if (!recursing)
10070  {
10071  /*
10072  * Because ALTER INDEX OWNER used to be allowed, and in fact
10073  * is generated by old versions of pg_dump, we give a warning
10074  * and do nothing rather than erroring out. Also, to avoid
10075  * unnecessary chatter while restoring those old dumps, say
10076  * nothing at all if the command would be a no-op anyway.
10077  */
10078  if (tuple_class->relowner != newOwnerId)
10079  ereport(WARNING,
10080  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10081  errmsg("cannot change owner of index \"%s\"",
10082  NameStr(tuple_class->relname)),
10083  errhint("Change the ownership of the index's table, instead.")));
10084  /* quick hack to exit via the no-op path */
10085  newOwnerId = tuple_class->relowner;
10086  }
10087  break;
10089  if (recursing)
10090  break;
10091  ereport(ERROR,
10092  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10093  errmsg("cannot change owner of index \"%s\"",
10094  NameStr(tuple_class->relname)),
10095  errhint("Change the ownership of the index's table, instead.")));
10096  break;
10097  case RELKIND_SEQUENCE:
10098  if (!recursing &&
10099  tuple_class->relowner != newOwnerId)
10100  {
10101  /* if it's an owned sequence, disallow changing it by itself */
10102  Oid tableId;
10103  int32 colId;
10104 
10105  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
10106  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
10107  ereport(ERROR,
10108  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10109  errmsg("cannot change owner of sequence \"%s\"",
10110  NameStr(tuple_class->relname)),
10111  errdetail("Sequence \"%s\" is linked to table \"%s\".",
10112  NameStr(tuple_class->relname),
10113  get_rel_name(tableId))));
10114  }
10115  break;
10117  if (recursing)
10118  break;
10119  ereport(ERROR,
10120  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10121  errmsg("\"%s\" is a composite type",
10122  NameStr(tuple_class->relname)),
10123  errhint("Use ALTER TYPE instead.")));
10124  break;
10125  case RELKIND_TOASTVALUE:
10126  if (recursing)
10127  break;
10128  /* FALL THRU */
10129  default:
10130  ereport(ERROR,
10131  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10132  errmsg("\"%s\" is not a table, view, sequence, or foreign table",
10133  NameStr(tuple_class->relname))));
10134  }
10135 
10136  /*
10137  * If the new owner is the same as the existing owner, consider the
10138  * command to have succeeded. This is for dump restoration purposes.
10139  */
10140  if (tuple_class->relowner != newOwnerId)
10141  {
10142  Datum repl_val[Natts_pg_class];
10143  bool repl_null[Natts_pg_class];
10144  bool repl_repl[Natts_pg_class];
10145  Acl *newAcl;
10146  Datum aclDatum;
10147  bool isNull;
10148  HeapTuple newtuple;
10149 
10150  /* skip permission checks when recursing to index or toast table */
10151  if (!recursing)
10152  {
10153  /* Superusers can always do it */
10154  if (!superuser())
10155  {
10156  Oid namespaceOid = tuple_class->relnamespace;
10157  AclResult aclresult;
10158 
10159  /* Otherwise, must be owner of the existing object */
10160  if (!pg_class_ownercheck(relationOid, GetUserId()))
10162  RelationGetRelationName(target_rel));
10163 
10164  /* Must be able to become new owner */
10165  check_is_member_of_role(GetUserId(), newOwnerId);
10166 
10167  /* New owner must have CREATE privilege on namespace */
10168  aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
10169  ACL_CREATE);
10170  if (aclresult != ACLCHECK_OK)
10171  aclcheck_error(aclresult, OBJECT_SCHEMA,
10172  get_namespace_name(namespaceOid));
10173  }
10174  }
10175 
10176  memset(repl_null, false, sizeof(repl_null));
10177  memset(repl_repl, false, sizeof(repl_repl));
10178 
10179  repl_repl[Anum_pg_class_relowner - 1] = true;
10180  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
10181 
10182  /*
10183  * Determine the modified ACL for the new owner. This is only
10184  * necessary when the ACL is non-null.
10185  */
10186  aclDatum = SysCacheGetAttr(RELOID, tuple,
10188  &isNull);
10189  if (!isNull)
10190  {
10191  newAcl = aclnewowner(DatumGetAclP(aclDatum),
10192  tuple_class->relowner, newOwnerId);
10193  repl_repl[Anum_pg_class_relacl - 1] = true;
10194  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
10195  }
10196 
10197  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
10198 
10199  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
10200 
10201  heap_freetuple(newtuple);
10202 
10203  /*
10204  * We must similarly update any per-column ACLs to reflect the new
10205  * owner; for neatness reasons that's split out as a subroutine.
10206  */
10207  change_owner_fix_column_acls(relationOid,
10208  tuple_class->relowner,
10209  newOwnerId);
10210 
10211  /*
10212  * Update owner dependency reference, if any. A composite type has
10213  * none, because it's tracked for the pg_type entry instead of here;
10214  * indexes and TOAST tables don't have their own entries either.
10215  */
10216  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
10217  tuple_class->relkind != RELKIND_INDEX &&
10218  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
10219  tuple_class->relkind != RELKIND_TOASTVALUE)
10221  newOwnerId);
10222 
10223  /*
10224  * Also change the ownership of the table's row type, if it has one
10225  */
10226  if (tuple_class->relkind != RELKIND_INDEX &&
10227  tuple_class->relkind != RELKIND_PARTITIONED_INDEX)
10228  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
10229 
10230  /*
10231  * If we are operating on a table or materialized view, also change
10232  * the ownership of any indexes and sequences that belong to the
10233  * relation, as well as its toast table (if it has one).
10234  */
10235  if (tuple_class->relkind == RELKIND_RELATION ||
10236  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
10237  tuple_class->relkind == RELKIND_MATVIEW ||
10238  tuple_class->relkind == RELKIND_TOASTVALUE)
10239  {
10240  List *index_oid_list;
10241  ListCell *i;
10242 
10243  /* Find all the indexes belonging to this relation */
10244  index_oid_list = RelationGetIndexList(target_rel);
10245 
10246  /* For each index, recursively change its ownership */
10247  foreach(i, index_oid_list)
10248  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
10249 
10250  list_free(index_oid_list);
10251  }
10252 
10253  if (tuple_class->relkind == RELKIND_RELATION ||
10254  tuple_class->relkind == RELKIND_MATVIEW)
10255  {
10256  /* If it has a toast table, recurse to change its ownership */
10257  if (tuple_class->reltoastrelid != InvalidOid)
10258  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
10259  true, lockmode);
10260 
10261  /* If it has dependent sequences, recurse to change them too */
10262  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
10263  }
10264  }
10265 
10267 
10268  ReleaseSysCache(tuple);
10269  heap_close(class_rel, RowExclusiveLock);
10270  relation_close(target_rel, NoLock);
10271 }
#define Natts_pg_class
Definition: pg_class.h:102
int errhint(const char *fmt,...)
Definition: elog.c:987
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define Anum_pg_class_relacl
Definition: pg_class.h:133
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:500
#define RelationGetDescr(relation)
Definition: rel.h:437
Oid GetUserId(void)
Definition: miscinit.c:284
#define DatumGetAclP(X)
Definition: acl.h:121
#define PointerGetDatum(X)
Definition: postgres.h:539
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
#define RelationRelationId
Definition: pg_class.h:29
#define RELKIND_MATVIEW
Definition: pg_class.h:165
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3450
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4690
#define RELKIND_COMPOSITE_TYPE
Definition: pg_class.h:166
signed int int32
Definition: c.h:302
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:304
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:82
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define RelationGetRelationName(relation)
Definition: rel.h:445
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
void check_is_member_of_role(Oid member, Oid role)
Definition: acl.c:4879
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
#define RELKIND_PARTITIONED_INDEX
Definition: pg_class.h:169
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:10037
#define WARNING
Definition: elog.h:40
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define RELKIND_TOASTVALUE
Definition: pg_class.h:163
AclResult
Definition: acl.h:178
uintptr_t Datum
Definition: postgres.h:365
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4752
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:10345
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4329
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:10280
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define RELKIND_VIEW
Definition: pg_class.h:164
void list_free(List *list)
Definition: list.c:1133
int i
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:565
#define RELKIND_INDEX
Definition: pg_class.h:161
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120
#define elog
Definition: elog.h:219
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:794
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RELKIND_SEQUENCE
Definition: pg_class.h:162
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1052
#define lfirst_oid(lc)
Definition: pg_list.h:108
#define Anum_pg_class_relowner
Definition: pg_class.h:107

◆ check_of_type()

void check_of_type ( HeapTuple  typetuple)

Definition at line 5179 of file tablecmds.c.

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

Referenced by ATExecAddOf(), and transformOfType().

5180 {
5181  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
5182  bool typeOk = false;
5183 
5184  if (typ->typtype == TYPTYPE_COMPOSITE)
5185  {
5186  Relation typeRelation;
5187 
5188  Assert(OidIsValid(typ->typrelid));
5189  typeRelation = relation_open(typ->typrelid, AccessShareLock);
5190  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
5191 
5192  /*
5193  * Close the parent rel, but keep our AccessShareLock on it until xact
5194  * commit. That will prevent someone else from deleting or ALTERing
5195  * the type before the typed table creation/conversion commits.
5196  */
5197  relation_close(typeRelation, NoLock);
5198  }
5199  if (!typeOk)
5200  ereport(ERROR,
5201  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5202  errmsg("type %s is not a composite type",
5203  format_type_be(HeapTupleGetOid(typetuple)))));
5204 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define TYPTYPE_COMPOSITE
Definition: pg_type.h:721
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
char * format_type_be(Oid type_oid)
Definition: format_type.c:320
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
Form_pg_class rd_rel
Definition: rel.h:114
#define OidIsValid(objectId)
Definition: c.h:594
#define RELKIND_COMPOSITE_TYPE
Definition: pg_class.h:166
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define ereport(elevel, rest)
Definition: elog.h:122
#define Assert(condition)
Definition: c.h:688
int errmsg(const char *fmt,...)
Definition: elog.c:797
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:700

◆ CheckTableNotInUse()

void CheckTableNotInUse ( Relation  rel,
const char *  stmt 
)

Definition at line 3115 of file tablecmds.c.

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

Referenced by AlterTable(), ATAddCheckConstraint(), ATExecAddColumn(), ATExecDropColumn(), ATExecDropConstraint(), ATPrepAlterColumnType(), ATSimpleRecursion(), ATTypedTableRecursion(), cluster_rel(), DefineIndex(), DefineVirtualRelation(), ExecRefreshMatView(), heap_drop_with_catalog(), index_drop(), reindex_index(), and truncate_check_rel().

3116 {
3117  int expected_refcnt;
3118 
3119  expected_refcnt = rel->rd_isnailed ? 2 : 1;
3120  if (rel->rd_refcnt != expected_refcnt)
3121  ereport(ERROR,
3122  (errcode(ERRCODE_OBJECT_IN_USE),
3123  /* translator: first %s is a SQL command, eg ALTER TABLE */
3124  errmsg("cannot %s \"%s\" because "
3125  "it is being used by active queries in this session",
3126  stmt, RelationGetRelationName(rel))));
3127 
3128  if (rel->rd_rel->relkind != RELKIND_INDEX &&
3129  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
3131  ereport(ERROR,
3132  (errcode(ERRCODE_OBJECT_IN_USE),
3133  /* translator: first %s is a SQL command, eg ALTER TABLE */
3134  errmsg("cannot %s \"%s\" because "
3135  "it has pending trigger events",
3136  stmt, RelationGetRelationName(rel))));
3137 }
bool rd_isnailed
Definition: rel.h:91
int errcode(int sqlerrcode)
Definition: elog.c:575
Form_pg_class rd_rel
Definition: rel.h:114
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:445
#define ereport(elevel, rest)
Definition: elog.h:122
#define RELKIND_PARTITIONED_INDEX
Definition: pg_class.h:169
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5367
int errmsg(const char *fmt,...)
Definition: elog.c:797
int rd_refcnt
Definition: rel.h:88
#define RELKIND_INDEX
Definition: pg_class.h:161
#define RelationGetRelid(relation)
Definition: rel.h:425

◆ DefineRelation()

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

Definition at line 517 of file tablecmds.c.

References AccessExclusiveLock, AccessShareLock, ACL_CREATE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, AddRelationNewConstraints(), allowSystemTableMods, Assert, RawColumnDefault::attnum, CookedConstraint::attnum, BuildDescForRelation(), check_default_allows_bound(), check_new_partition_bound(), CommandCounterIncrement(), ComputePartitionAttrs(), CookedConstraint::conoid, CONSTR_DEFAULT, CreateStmt::constraints, CookedConstraint::contype, convert_tuples_by_name_map(), ColumnDef::cooked_default, DefineIndex(), elog, ereport, errcode(), errmsg(), ERROR, CookedConstraint::expr, generateClonedIndexStmt(), get_default_oid_from_partdesc(), get_tablespace_name(), get_tablespace_oid(), GetDefaultTablespace(), gettext_noop, GetUserId(), GLOBALTABLESPACE_OID, heap_close, heap_create_with_catalog(), heap_open(), HEAP_RELOPT_NAMESPACES, heap_reloptions(), ColumnDef::identity, index_close(), index_open(), CookedConstraint::inhcount, CreateStmt::inhRelations, InSecurityRestrictedOperation(), interpretOidsOption(), InvalidOid, PartitionBoundSpec::is_default, CookedConstraint::is_local, CookedConstraint::is_no_inherit, lappend(), lfirst, lfirst_oid, linitial_oid, list_concat(), list_free(), list_length(), make_parsestate(), MergeAttributes(), MyDatabaseTableSpace, CookedConstraint::name, NAMEDATALEN, NIL, NoLock, OBJECT_TABLESPACE, ObjectAddressSet, CreateStmt::ofTypename, OidIsValid, CreateStmt::oncommit, ONCOMMIT_NOOP, CreateStmt::options, ParseState::p_sourcetext, palloc(), CreateStmt::partbound, PARTITION_MAX_KEYS, PartitionSpec::partParams, CreateStmt::partspec, pg_tablespace_aclcheck(), pg_type_aclcheck(), RangeVarGetAndCheckCreationNamespace(), RawColumnDefault::raw_default, ColumnDef::raw_default, RelationData::rd_rel, CreateStmt::relation, relation_close(), relation_open(), RelationGetDescr, RelationGetIndexList(), RelationGetPartitionDesc, RelationGetRelationName, RelationGetRelid, RelationRelationId, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RELKIND_VIEW, RangeVar::relname, RangeVar::relpersistence, RELPERSISTENCE_TEMP, CookedConstraint::skip_validation, StoreCatalogInheritance(), StorePartitionBound(), StorePartitionKey(), StrNCpy, CreateStmt::tableElts, CreateStmt::tablespacename, tupleDesc::tdhasoid, transformPartitionBound(), transformPartitionSpec(), transformRelOptions(), TupleDescAttr, typenameTypeId(), update_default_partition_oid(), and view_reloptions().

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

519 {
520  char relname[NAMEDATALEN];
521  Oid namespaceId;
522  Oid relationId;
523  Oid tablespaceId;
524  Relation rel;
526  List *inheritOids;
527  List *old_constraints;
528  bool localHasOids;
529  int parentOidCount;
530  List *rawDefaults;
531  List *cookedDefaults;
532  Datum reloptions;
533  ListCell *listptr;
534  AttrNumber attnum;
535  static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
536  Oid ofTypeId;
537  ObjectAddress address;
538 
539  /*
540  * Truncate relname to appropriate length (probably a waste of time, as
541  * parser should have done this already).
542  */
543  StrNCpy(relname, stmt->relation->relname, NAMEDATALEN);
544 
545  /*
546  * Check consistency of arguments
547  */
548  if (stmt->oncommit != ONCOMMIT_NOOP
550  ereport(ERROR,
551  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
552  errmsg("ON COMMIT can only be used on temporary tables")));
553 
554  if (stmt->partspec != NULL)
555  {
556  if (relkind != RELKIND_RELATION)
557  elog(ERROR, "unexpected relkind: %d", (int) relkind);
558 
559  relkind = RELKIND_PARTITIONED_TABLE;
560  }
561 
562  /*
563  * Look up the namespace in which we are supposed to create the relation,
564  * check we have permission to create there, lock it against concurrent
565  * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
566  * namespace is selected.
567  */
568  namespaceId =
570 
571  /*
572  * Security check: disallow creating temp tables from security-restricted
573  * code. This is needed because calling code might not expect untrusted
574  * tables to appear in pg_temp at the front of its search path.
575  */
578  ereport(ERROR,
579  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
580  errmsg("cannot create temporary table within security-restricted operation")));
581 
582  /*
583  * Select tablespace to use. If not specified, use default tablespace
584  * (which may in turn default to database's default).
585  */
586  if (stmt->tablespacename)
587  {
588  tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
589  }
590  else
591  {
592  tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence);
593  /* note InvalidOid is OK in this case */
594  }
595 
596  /* Check permissions except when using database's default */
597  if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
598  {
599  AclResult aclresult;
600 
601  aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
602  ACL_CREATE);
603  if (aclresult != ACLCHECK_OK)
605  get_tablespace_name(tablespaceId));
606  }
607 
608  /* In all cases disallow placing user relations in pg_global */
609  if (tablespaceId == GLOBALTABLESPACE_OID)
610  ereport(ERROR,
611  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
612  errmsg("only shared relations can be placed in pg_global tablespace")));
613 
614  /* Identify user ID that will own the table */
615  if (!OidIsValid(ownerId))
616  ownerId = GetUserId();
617 
618  /*
619  * Parse and validate reloptions, if any.
620  */
621  reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
622  true, false);
623 
624  if (relkind == RELKIND_VIEW)
625  (void) view_reloptions(reloptions, true);
626  else
627  (void) heap_reloptions(relkind, reloptions, true);
628 
629  if (stmt->ofTypename)
630  {
631  AclResult aclresult;
632 
633  ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
634 
635  aclresult = pg_type_aclcheck(ofTypeId, GetUserId(), ACL_USAGE);
636  if (aclresult != ACLCHECK_OK)
637  aclcheck_error_type(aclresult, ofTypeId);
638  }
639  else
640  ofTypeId = InvalidOid;
641 
642  /*
643  * Look up inheritance ancestors and generate relation schema, including
644  * inherited attributes. (Note that stmt->tableElts is destructively
645  * modified by MergeAttributes.)
646  */
647  stmt->tableElts =
649  stmt->relation->relpersistence,
650  stmt->partbound != NULL,
651  &inheritOids, &old_constraints, &parentOidCount);
652 
653  /*
654  * Create a tuple descriptor from the relation schema. Note that this
655  * deals with column names, types, and NOT NULL constraints, but not
656  * default values or CHECK constraints; we handle those below.
657  */
658  descriptor = BuildDescForRelation(stmt->tableElts);
659 
660  /*
661  * Notice that we allow OIDs here only for plain tables and partitioned
662  * tables, even though some other relkinds can support them. This is
663  * necessary because the default_with_oids GUC must apply only to plain
664  * tables and not any other relkind; doing otherwise would break existing
665  * pg_dump files. We could allow explicit "WITH OIDS" while not allowing
666  * default_with_oids to affect other relkinds, but it would complicate
667  * interpretOidsOption().
668  */
669  localHasOids = interpretOidsOption(stmt->options,
670  (relkind == RELKIND_RELATION ||
671  relkind == RELKIND_PARTITIONED_TABLE));
672  descriptor->tdhasoid = (localHasOids || parentOidCount > 0);
673 
674  /*
675  * If a partitioned table doesn't have the system OID column, then none of
676  * its partitions should have it.
677  */
678  if (stmt->partbound && parentOidCount == 0 && localHasOids)
679  ereport(ERROR,
680  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
681  errmsg("cannot create table with OIDs as partition of table without OIDs")));
682 
683  /*
684  * Find columns with default values and prepare for insertion of the
685  * defaults. Pre-cooked (that is, inherited) defaults go into a list of
686  * CookedConstraint structs that we'll pass to heap_create_with_catalog,
687  * while raw defaults go into a list of RawColumnDefault structs that will
688  * be processed by AddRelationNewConstraints. (We can't deal with raw
689  * expressions until we can do transformExpr.)
690  *
691  * We can set the atthasdef flags now in the tuple descriptor; this just
692  * saves StoreAttrDefault from having to do an immediate update of the
693  * pg_attribute rows.
694  */
695  rawDefaults = NIL;
696  cookedDefaults = NIL;
697  attnum = 0;
698 
699  foreach(listptr, stmt->tableElts)
700  {
701  ColumnDef *colDef = lfirst(listptr);
702  Form_pg_attribute attr;
703 
704  attnum++;
705  attr = TupleDescAttr(descriptor, attnum - 1);
706 
707  if (colDef->raw_default != NULL)
708  {
709  RawColumnDefault *rawEnt;
710 
711  Assert(colDef->cooked_default == NULL);
712 
713  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
714  rawEnt->attnum = attnum;
715  rawEnt->raw_default = colDef->raw_default;
716  rawDefaults = lappend(rawDefaults, rawEnt);
717  attr->atthasdef = true;
718  }
719  else if (colDef->cooked_default != NULL)
720  {
721  CookedConstraint *cooked;
722 
723  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
724  cooked->contype = CONSTR_DEFAULT;
725  cooked->conoid = InvalidOid; /* until created */
726  cooked->name = NULL;
727  cooked->attnum = attnum;
728  cooked->expr = colDef->cooked_default;
729  cooked->skip_validation = false;
730  cooked->is_local = true; /* not used for defaults */
731  cooked->inhcount = 0; /* ditto */
732  cooked->is_no_inherit = false;
733  cookedDefaults = lappend(cookedDefaults, cooked);
734  attr->atthasdef = true;
735  }
736 
737  if (colDef->identity)
738  attr->attidentity = colDef->identity;
739  }
740 
741  /*
742  * Create the relation. Inherited defaults and constraints are passed in
743  * for immediate handling --- since they don't need parsing, they can be
744  * stored immediately.
745  */
746  relationId = heap_create_with_catalog(relname,
747  namespaceId,
748  tablespaceId,
749  InvalidOid,
750  InvalidOid,
751  ofTypeId,
752  ownerId,
753  descriptor,
754  list_concat(cookedDefaults,
755  old_constraints),
756  relkind,
757  stmt->relation->relpersistence,
758  false,
759  false,
760  localHasOids,
761  parentOidCount,
762  stmt->oncommit,
763  reloptions,
764  true,
766  false,
767  typaddress);
768 
769  /* Store inheritance information for new rel. */
770  StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
771 
772  /*
773  * We must bump the command counter to make the newly-created relation
774  * tuple visible for opening.
775  */
777 
778  /*
779  * Open the new relation and acquire exclusive lock on it. This isn't
780  * really necessary for locking out other backends (since they can't see
781  * the new rel anyway until we commit), but it keeps the lock manager from
782  * complaining about deadlock risks.
783  */
784  rel = relation_open(relationId, AccessExclusiveLock);
785 
786  /* Process and store partition bound, if any. */
787  if (stmt->partbound)
788  {
789  PartitionBoundSpec *bound;
790  ParseState *pstate;
791  Oid parentId = linitial_oid(inheritOids),
792  defaultPartOid;
793  Relation parent,
794  defaultRel = NULL;
795 
796  /* Already have strong enough lock on the parent */
797  parent = heap_open(parentId, NoLock);
798 
799  /*
800  * We are going to try to validate the partition bound specification
801  * against the partition key of parentRel, so it better have one.
802  */
803  if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
804  ereport(ERROR,
805  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
806  errmsg("\"%s\" is not partitioned",
807  RelationGetRelationName(parent))));
808 
809  /*
810  * The partition constraint of the default partition depends on the
811  * partition bounds of every other partition. It is possible that
812  * another backend might be about to execute a query on the default
813  * partition table, and that the query relies on previously cached
814  * default partition constraints. We must therefore take a table lock
815  * strong enough to prevent all queries on the default partition from
816  * proceeding until we commit and send out a shared-cache-inval notice
817  * that will make them update their index lists.
818  *
819  * Order of locking: The relation being added won't be visible to
820  * other backends until it is committed, hence here in
821  * DefineRelation() the order of locking the default partition and the
822  * relation being added does not matter. But at all other places we
823  * need to lock the default relation before we lock the relation being
824  * added or removed i.e. we should take the lock in same order at all
825  * the places such that lock parent, lock default partition and then
826  * lock the partition so as to avoid a deadlock.
827  */
828  defaultPartOid =
830  if (OidIsValid(defaultPartOid))
831  defaultRel = heap_open(defaultPartOid, AccessExclusiveLock);
832 
833  /* Tranform the bound values */
834  pstate = make_parsestate(NULL);
835  pstate->p_sourcetext = queryString;
836 
837  bound = transformPartitionBound(pstate, parent, stmt->partbound);
838 
839  /*
840  * Check first that the new partition's bound is valid and does not
841  * overlap with any of existing partitions of the parent.
842  */
843  check_new_partition_bound(relname, parent, bound);
844 
845  /*
846  * If the default partition exists, its partition constraints will
847  * change after the addition of this new partition such that it won't
848  * allow any row that qualifies for this new partition. So, check that
849  * the existing data in the default partition satisfies the constraint
850  * as it will exist after adding this partition.
851  */
852  if (OidIsValid(defaultPartOid))
853  {
854  check_default_allows_bound(parent, defaultRel, bound);
855  /* Keep the lock until commit. */
856  heap_close(defaultRel, NoLock);
857  }
858 
859  /* Update the pg_class entry. */
860  StorePartitionBound(rel, parent, bound);
861 
862  /* Update the default partition oid */
863  if (bound->is_default)
864  update_default_partition_oid(RelationGetRelid(parent), relationId);
865 
866  heap_close(parent, NoLock);
867 
868  /*
869  * The code that follows may also update the pg_class tuple to update
870  * relnumchecks, so bump up the command counter to avoid the "already
871  * updated by self" error.
872  */
874  }
875 
876  /*
877  * Process the partitioning specification (if any) and store the partition
878  * key information into the catalog.
879  */
880  if (stmt->partspec)
881  {
882  char strategy;
883  int partnatts;
884  AttrNumber partattrs[PARTITION_MAX_KEYS];
885  Oid partopclass[PARTITION_MAX_KEYS];
886  Oid partcollation[PARTITION_MAX_KEYS];
887  List *partexprs = NIL;
888 
889  partnatts = list_length(stmt->partspec->partParams);
890 
891  /* Protect fixed-size arrays here and in executor */
892  if (partnatts > PARTITION_MAX_KEYS)
893  ereport(ERROR,
894  (errcode(ERRCODE_TOO_MANY_COLUMNS),
895  errmsg("cannot partition using more than %d columns",
897 
898  /*
899  * We need to transform the raw parsetrees corresponding to partition
900  * expressions into executable expression trees. Like column defaults
901  * and CHECK constraints, we could not have done the transformation
902  * earlier.
903  */
904  stmt->partspec = transformPartitionSpec(rel, stmt->partspec,
905  &strategy);
906 
908  partattrs, &partexprs, partopclass,
909  partcollation, strategy);
910 
911  StorePartitionKey(rel, strategy, partnatts, partattrs, partexprs,
912  partopclass, partcollation);
913 
914  /* make it all visible */
916  }
917 
918  /*
919  * If we're creating a partition, create now all the indexes defined in
920  * the parent. We can't do it earlier, because DefineIndex wants to know
921  * the partition key which we just stored.
922  */
923  if (stmt->partbound)
924  {
925  Oid parentId = linitial_oid(inheritOids);
926  Relation parent;
927  List *idxlist;
928  ListCell *cell;
929 
930  /* Already have strong enough lock on the parent */
931  parent = heap_open(parentId, NoLock);
932  idxlist = RelationGetIndexList(parent);
933 
934  /*
935  * For each index in the parent table, create one in the partition
936  */
937  foreach(cell, idxlist)
938  {
940  AttrNumber *attmap;
941  IndexStmt *idxstmt;
942  Oid constraintOid;
943 
945  RelationGetDescr(parent),
946  gettext_noop("could not convert row type"));
947  idxstmt =
948  generateClonedIndexStmt(NULL, RelationGetRelid(rel), idxRel,
949  attmap, RelationGetDescr(rel)->natts,
950  &constraintOid);
952  idxstmt,
953  InvalidOid,
954  RelationGetRelid(idxRel),
955  constraintOid,
956  false, false, false, false, false);
957 
958  index_close(idxRel, AccessShareLock);
959  }
960 
961  list_free(idxlist);
962  heap_close(parent, NoLock);
963  }
964 
965  /*
966  * Now add any newly specified column default values and CHECK constraints
967  * to the new relation. These are passed to us in the form of raw
968  * parsetrees; we need to transform them to executable expression trees
969  * before they can be added. The most convenient way to do that is to
970  * apply the parser's transformExpr routine, but transformExpr doesn't
971  * work unless we have a pre-existing relation. So, the transformation has
972  * to be postponed to this final step of CREATE TABLE.
973  */
974  if (rawDefaults || stmt->constraints)
975  AddRelationNewConstraints(rel, rawDefaults, stmt->constraints,
976  true, true, false);
977 
978  ObjectAddressSet(address, RelationRelationId, relationId);
979 
980  /*
981  * Clean up. We keep lock on new relation (although it shouldn't be
982  * visible to anyone else anyway, until commit).
983  */
984  relation_close(rel, NoLock);
985 
986  return address;
987 }
RangeVar * relation
Definition: parsenodes.h:2011
bytea * heap_reloptions(char relkind, Datum reloptions, bool validate)
Definition: reloptions.c:1420
#define NIL
Definition: pg_list.h:69
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1380
OnCommitAction oncommit
Definition: parsenodes.h:2020
List * inhRelations
Definition: parsenodes.h:2013
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4702
ObjectAddress DefineIndex(Oid relationId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition: indexcmds.c:319
bool is_no_inherit
Definition: heap.h:38
bool tdhasoid
Definition: tupdesc.h:82
void StorePartitionKey(Relation rel, char strategy, int16 partnatts, AttrNumber *partattrs, List *partexprs, Oid *partopclass, Oid *partcollation)
Definition: heap.c:3116
AttrNumber attnum
Definition: heap.h:24
List * partParams
Definition: parsenodes.h:790
#define RelationGetDescr(relation)
Definition: rel.h:437
Oid GetUserId(void)
Definition: miscinit.c:284
char identity
Definition: parsenodes.h:655
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
#define RelationRelationId
Definition: pg_class.h:29
void update_default_partition_oid(Oid parentId, Oid defaultPartId)
Definition: partition.c:3166
#define AccessShareLock
Definition: lockdefs.h:36
#define GLOBALTABLESPACE_OID
Definition: pg_tablespace.h:64
#define gettext_noop(x)
Definition: c.h:1025
int errcode(int sqlerrcode)
Definition: elog.c:575
#define PARTITION_MAX_KEYS
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
List * list_concat(List *list1, List *list2)
Definition: list.c:321
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
static void ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, char strategy)
Definition: tablecmds.c:13446
#define OidIsValid(objectId)
Definition: c.h:594
void check_default_allows_bound(Relation parent, Relation default_rel, PartitionBoundSpec *new_spec)
Definition: partition.c:1242
static void StoreCatalogInheritance(Oid relationId, List *supers, bool child_is_partition)
Definition: tablecmds.c:2418
void check_new_partition_bound(char *relname, Relation parent, PartitionBoundSpec *spec)
Definition: partition.c:954
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, char *validnsps[], bool ignoreOids, bool isReset)
Definition: reloptions.c:755
Oid GetDefaultTablespace(char relpersistence)
Definition: tablespace.c:1111
static PartitionSpec * transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
Definition: tablecmds.c:13361
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3663
Oid MyDatabaseTableSpace
Definition: globals.c:79
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
bytea * view_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:1388
List * constraints
Definition: parsenodes.h:2018
PartitionBoundSpec * transformPartitionBound(ParseState *pstate, Relation parent, PartitionBoundSpec *spec)
#define NAMEDATALEN
PartitionBoundSpec * partbound
Definition: parsenodes.h:2015
Node * cooked_default
Definition: parsenodes.h:654
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
AttrNumber attnum
Definition: heap.h:33
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:82
int inhcount
Definition: heap.h:37
#define NoLock
Definition: lockdefs.h:34
IndexStmt * generateClonedIndexStmt(RangeVar *heapRel, Oid heapRelid, Relation source_idx, const AttrNumber *attmap, int attmap_length, Oid *constraintOid)
#define RelationGetRelationName(relation)
Definition: rel.h:445
List * options
Definition: parsenodes.h:2019
Node * raw_default
Definition: heap.h:25
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define ACL_USAGE
Definition: parsenodes.h:80
bool skip_validation
Definition: heap.h:35
#define HEAP_RELOPT_NAMESPACES
Definition: reloptions.h:59
const char * p_sourcetext
Definition: parse_node.h:173
ConstrType contype
Definition: heap.h:30
#define ereport(elevel, rest)
Definition: elog.h:122
Node * raw_default
Definition: parsenodes.h:653
List * lappend(List *list, void *datum)
Definition: list.c:128
char * tablespacename
Definition: parsenodes.h:2021
AttrNumber * convert_tuples_by_name_map(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:293
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:508
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
AclResult
Definition: acl.h:178
uintptr_t Datum
Definition: postgres.h:365
void CommandCounterIncrement(void)
Definition: xact.c:915
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
bool allowSystemTableMods
Definition: globals.c:112
#define InvalidOid
Definition: postgres_ext.h:36
void StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound)
Definition: heap.c:3256
List * tableElts
Definition: parsenodes.h:2012
#define Assert(condition)
Definition: c.h:688
#define lfirst(lc)
Definition: pg_list.h:106
#define StrNCpy(dst, src, len)
Definition: c.h:870
bool InSecurityRestrictedOperation(void)
Definition: miscinit.c:416
#define linitial_oid(l)
Definition: pg_list.h:113
static int list_length(const List *l)
Definition: pg_list.h:89
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4329
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
char relpersistence
Definition: primnodes.h:71
bool interpretOidsOption(List *defList, bool allowOids)
Definition: parse_clause.c:262
static List * MergeAttributes(List *schema, List *supers, char relpersistence, bool is_partition, List **supOids, List **supconstr, int *supOidCount)
Definition: tablecmds.c:1739
#define AccessExclusiveLock
Definition: lockdefs.h:45
void * palloc(Size size)
Definition: mcxt.c:835
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1426
#define RELKIND_VIEW
Definition: pg_class.h:164
void list_free(List *list)
Definition: list.c:1133
Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid reltypeid, Oid reloftypeid, Oid ownerid, TupleDesc tupdesc, List *cooked_constraints, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, bool oidislocal, int oidinhcount, OnCommitAction oncommit, Datum reloptions, bool use_user_acl, bool allow_system_table_mods, bool is_internal, ObjectAddress *typaddress)
Definition: heap.c:1022
Oid conoid
Definition: heap.h:31
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120
Node * expr
Definition: heap.h:34
#define elog
Definition: elog.h:219
TupleDesc BuildDescForRelation(List *schema)
Definition: tupdesc.c:727
#define RELPERSISTENCE_TEMP
Definition: pg_class.h:173
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4740
#define RELKIND_RELATION
Definition: pg_class.h:160
PartitionSpec * partspec
Definition: parsenodes.h:2016
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
char * name
Definition: heap.h:32
#define RelationGetRelid(relation)
Definition: rel.h:425
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition: partition.c:3124
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal)
Definition: heap.c:2230
TypeName * ofTypename
Definition: parsenodes.h:2017
#define lfirst_oid(lc)
Definition: pg_list.h:108
#define RelationGetPartitionDesc(relation)
Definition: rel.h:641
bool is_local
Definition: heap.h:36
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274

◆ ExecuteTruncate()

void ExecuteTruncate ( TruncateStmt stmt)

Definition at line 1314 of file tablecmds.c.

References AccessExclusiveLock, aclcheck_error(), ACLCHECK_NOT_OWNER, AfterTriggerBeginQuery(), AfterTriggerEndQuery(), TruncateStmt::behavior, CheckTableForSerializableConflictIn(), CreateExecutorState(), DROP_CASCADE, DROP_RESTRICT, ereport, errcode(), errhint(), errmsg(), ERROR, EState::es_num_result_relations, EState::es_result_relation_info, EState::es_result_relations, ExecASTruncateTriggers(), ExecBSTruncateTriggers(), find_all_inheritors(), FreeExecutorState(), GetCurrentSubTransactionId(), GetOldestMultiXactId(), getOwnedSequences(), GetUserId(), heap_close, heap_create_init_fork(), heap_open(), heap_openrv(), heap_truncate_check_FKs(), heap_truncate_find_FKs(), heap_truncate_one_rel(), RangeVar::inh, InitResultRelInfo(), lappend(), lappend_oid(), lfirst, lfirst_oid, list_length(), list_member_oid(), NIL, NoLock, NOTICE, OBJECT_SEQUENCE, OidIsValid, palloc(), pg_class_ownercheck(), pgstat_count_truncate(), RelationData::rd_createSubid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_rel, RecentXmin, REINDEX_REL_PROCESS_TOAST, reindex_relation(), relation_close(), relation_open(), RelationGetRelationName, RelationGetRelid, TruncateStmt::relations, RelationSetNewRelfilenode(), OnCommitItem::relid, RELKIND_PARTITIONED_TABLE, RELPERSISTENCE_UNLOGGED, ResetSequence(), TruncateStmt::restart_seqs, and truncate_check_rel().

Referenced by standard_ProcessUtility().

1315 {
1316  List *rels = NIL;
1317  List *relids = NIL;
1318  List *seq_relids = NIL;
1319  EState *estate;
1320  ResultRelInfo *resultRelInfos;
1321  ResultRelInfo *resultRelInfo;
1322  SubTransactionId mySubid;
1323  ListCell *cell;
1324 
1325  /*
1326  * Open, exclusive-lock, and check all the explicitly-specified relations
1327  */
1328  foreach(cell, stmt->relations)
1329  {
1330  RangeVar *rv = lfirst(cell);
1331  Relation rel;
1332  bool recurse = rv->inh;
1333  Oid myrelid;
1334 
1335  rel = heap_openrv(rv, AccessExclusiveLock);
1336  myrelid = RelationGetRelid(rel);
1337  /* don't throw error for "TRUNCATE foo, foo" */
1338  if (list_member_oid(relids, myrelid))
1339  {
1341  continue;
1342  }
1343  truncate_check_rel(rel);
1344  rels = lappend(rels, rel);
1345  relids = lappend_oid(relids, myrelid);
1346 
1347  if (recurse)
1348  {
1349  ListCell *child;
1350  List *children;
1351 
1352  children = find_all_inheritors(myrelid, AccessExclusiveLock, NULL);
1353 
1354  foreach(child, children)
1355  {
1356  Oid childrelid = lfirst_oid(child);
1357 
1358  if (list_member_oid(relids, childrelid))
1359  continue;
1360 
1361  /* find_all_inheritors already got lock */
1362  rel = heap_open(childrelid, NoLock);
1363  truncate_check_rel(rel);
1364  rels = lappend(rels, rel);
1365  relids = lappend_oid(relids, childrelid);
1366  }
1367  }
1368  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1369  ereport(ERROR,
1370  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1371  errmsg("cannot truncate only a partitioned table"),
1372  errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1373  }
1374 
1375  /*
1376  * In CASCADE mode, suck in all referencing relations as well. This
1377  * requires multiple iterations to find indirectly-dependent relations. At
1378  * each phase, we need to exclusive-lock new rels before looking for their
1379  * dependencies, else we might miss something. Also, we check each rel as
1380  * soon as we open it, to avoid a faux pas such as holding lock for a long
1381  * time on a rel we have no permissions for.
1382  */
1383  if (stmt->behavior == DROP_CASCADE)
1384  {
1385  for (;;)
1386  {
1387  List *newrelids;
1388 
1389  newrelids = heap_truncate_find_FKs(relids);
1390  if (newrelids == NIL)
1391  break; /* nothing else to add */
1392 
1393  foreach(cell, newrelids)
1394  {
1395  Oid relid = lfirst_oid(cell);
1396  Relation rel;
1397 
1398  rel = heap_open(relid, AccessExclusiveLock);
1399  ereport(NOTICE,
1400  (errmsg("truncate cascades to table \"%s\"",
1401  RelationGetRelationName(rel))));
1402  truncate_check_rel(rel);
1403  rels = lappend(rels, rel);
1404  relids = lappend_oid(relids, relid);
1405  }
1406  }
1407  }
1408 
1409  /*
1410  * Check foreign key references. In CASCADE mode, this should be
1411  * unnecessary since we just pulled in all the references; but as a
1412  * cross-check, do it anyway if in an Assert-enabled build.
1413  */
1414 #ifdef USE_ASSERT_CHECKING
1415  heap_truncate_check_FKs(rels, false);
1416 #else
1417  if (stmt->behavior == DROP_RESTRICT)
1418  heap_truncate_check_FKs(rels, false);
1419 #endif
1420 
1421  /*
1422  * If we are asked to restart sequences, find all the sequences, lock them
1423  * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1424  * We want to do this early since it's pointless to do all the truncation
1425  * work only to fail on sequence permissions.
1426  */
1427  if (stmt->restart_seqs)
1428  {
1429  foreach(cell, rels)
1430  {
1431  Relation rel = (Relation) lfirst(cell);
1432  List *seqlist = getOwnedSequences(RelationGetRelid(rel), 0);
1433  ListCell *seqcell;
1434 
1435  foreach(seqcell, seqlist)
1436  {
1437  Oid seq_relid = lfirst_oid(seqcell);
1438  Relation seq_rel;
1439 
1440  seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1441 
1442  /* This check must match AlterSequence! */
1443  if (!pg_class_ownercheck(seq_relid, GetUserId()))
1445  RelationGetRelationName(seq_rel));
1446 
1447  seq_relids = lappend_oid(seq_relids, seq_relid);
1448 
1449  relation_close(seq_rel, NoLock);
1450  }
1451  }
1452  }
1453 
1454  /* Prepare to catch AFTER triggers. */
1456 
1457  /*
1458  * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1459  * each relation. We don't need to call ExecOpenIndices, though.
1460  */
1461  estate = CreateExecutorState();
1462  resultRelInfos = (ResultRelInfo *)
1463  palloc(list_length(rels) * sizeof(ResultRelInfo));
1464  resultRelInfo = resultRelInfos;
1465  foreach(cell, rels)
1466  {
1467  Relation rel = (Relation) lfirst(cell);
1468 
1469  InitResultRelInfo(resultRelInfo,
1470  rel,
1471  0, /* dummy rangetable index */
1472  NULL,
1473  0);
1474  resultRelInfo++;
1475  }
1476  estate->es_result_relations = resultRelInfos;
1477  estate->es_num_result_relations = list_length(rels);
1478 
1479  /*
1480  * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
1481  * truncating (this is because one of them might throw an error). Also, if
1482  * we were to allow them to prevent statement execution, that would need
1483  * to be handled here.
1484  */
1485  resultRelInfo = resultRelInfos;
1486  foreach(cell, rels)
1487  {
1488  estate->es_result_relation_info = resultRelInfo;
1489  ExecBSTruncateTriggers(estate, resultRelInfo);
1490  resultRelInfo++;
1491  }
1492 
1493  /*
1494  * OK, truncate each table.
1495  */
1496  mySubid = GetCurrentSubTransactionId();
1497 
1498  foreach(cell, rels)
1499  {
1500  Relation rel = (Relation) lfirst(cell);
1501 
1502  /* Skip partitioned tables as there is nothing to do */
1503  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1504  continue;
1505 
1506  /*
1507  * Normally, we need a transaction-safe truncation here. However, if
1508  * the table was either created in the current (sub)transaction or has
1509  * a new relfilenode in the current (sub)transaction, then we can just
1510  * truncate it in-place, because a rollback would cause the whole
1511  * table or the current physical file to be thrown away anyway.
1512  */
1513  if (rel->rd_createSubid == mySubid ||
1514  rel->rd_newRelfilenodeSubid == mySubid)
1515  {
1516  /* Immediate, non-rollbackable truncation is OK */
1517  heap_truncate_one_rel(rel);
1518  }
1519  else
1520  {
1521  Oid heap_relid;
1522  Oid toast_relid;
1523  MultiXactId minmulti;
1524 
1525  /*
1526  * This effectively deletes all rows in the table, and may be done
1527  * in a serializable transaction. In that case we must record a
1528  * rw-conflict in to this transaction from each transaction
1529  * holding a predicate lock on the table.
1530  */
1532 
1533  minmulti = GetOldestMultiXactId();
1534 
1535  /*
1536  * Need the full transaction-safe pushups.
1537  *
1538  * Create a new empty storage file for the relation, and assign it
1539  * as the relfilenode value. The old storage file is scheduled for
1540  * deletion at commit.
1541  */
1542  RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence,
1543  RecentXmin, minmulti);
1544  if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
1545  heap_create_init_fork(rel);
1546 
1547  heap_relid = RelationGetRelid(rel);
1548  toast_relid = rel->rd_rel->reltoastrelid;
1549 
1550  /*
1551  * The same for the toast table, if any.
1552  */
1553  if (OidIsValid(toast_relid))
1554  {
1555  rel = relation_open(toast_relid, AccessExclusiveLock);
1556  RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence,
1557  RecentXmin, minmulti);
1558  if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
1559  heap_create_init_fork(rel);
1560  heap_close(rel, NoLock);
1561  }
1562 
1563  /*
1564  * Reconstruct the indexes to match, and we're done.
1565  */
1567  }
1568 
1569  pgstat_count_truncate(rel);
1570  }
1571 
1572  /*
1573  * Restart owned sequences if we were asked to.
1574  */
1575  foreach(cell, seq_relids)
1576  {
1577  Oid seq_relid = lfirst_oid(cell);
1578 
1579  ResetSequence(seq_relid);
1580  }
1581 
1582  /*
1583  * Process all AFTER STATEMENT TRUNCATE triggers.
1584  */
1585  resultRelInfo = resultRelInfos;
1586  foreach(cell, rels)
1587  {
1588  estate->es_result_relation_info = resultRelInfo;
1589  ExecASTruncateTriggers(estate, resultRelInfo);
1590  resultRelInfo++;
1591  }
1592 
1593  /* Handle queued AFTER triggers */
1594  AfterTriggerEndQuery(estate);
1595 
1596  /* We can clean up the EState now */
1597  FreeExecutorState(estate);
1598 
1599  /* And close the rels (can't do this while EState still holds refs) */
1600  foreach(cell, rels)
1601  {
1602  Relation rel = (Relation) lfirst(cell);
1603 
1604  heap_close(rel, NoLock);
1605  }
1606 }
#define NIL
Definition: pg_list.h:69
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, Relation partition_root, int instrument_options)
Definition: execMain.c:1306
void RelationSetNewRelfilenode(Relation relation, char persistence, TransactionId freezeXid, MultiXactId minmulti)
Definition: relcache.c:3399
int errhint(const char *fmt,...)
Definition: elog.c:987
#define RELPERSISTENCE_UNLOGGED
Definition: pg_class.h:172
Oid GetUserId(void)
Definition: miscinit.c:284
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:2903
int errcode(int sqlerrcode)
Definition: elog.c:575
TransactionId RecentXmin
Definition: snapmgr.c:165
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:2940
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:111
uint32 SubTransactionId
Definition: c.h:467
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:594
void FreeExecutorState(EState *estate)
Definition: execUtils.c:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
DropBehavior behavior
Definition: parsenodes.h:2602
struct RelationData * Relation
Definition: relcache.h:26
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:2949
#define ERROR
Definition: elog.h:43
struct ResultRelInfo ResultRelInfo
List * relations
Definition: parsenodes.h:2600
#define NoLock
Definition: lockdefs.h:34
void heap_create_init_fork(Relation rel)
Definition: heap.c:1383
ResultRelInfo * es_result_relations
Definition: execnodes.h:455
bool restart_seqs
Definition: parsenodes.h:2601
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3001
#define RelationGetRelationName(relation)
Definition: rel.h:445
void pgstat_count_truncate(Relation rel)
Definition: pgstat.c:2008
#define ereport(elevel, rest)
Definition: elog.h:122
EState * CreateExecutorState(void)
Definition: execUtils.c:80
bool inh
Definition: primnodes.h:69
List * lappend(List *list, void *datum)
Definition: list.c:128
SubTransactionId rd_createSubid
Definition: rel.h:110
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
MultiXactId GetOldestMultiXactId(void)
Definition: multixact.c:2491
List * getOwnedSequences(Oid relid, AttrNumber attnum)
Definition: pg_depend.c:548
static void truncate_check_rel(Relation rel)
Definition: tablecmds.c:1612
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
int es_num_result_relations
Definition: execnodes.h:456
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1319
#define NOTICE
Definition: elog.h:37
void AfterTriggerBeginQuery(void)
Definition: trigger.c:4533
TransactionId MultiXactId
Definition: c.h:473
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define lfirst(lc)
Definition: pg_list.h:106
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:642
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4752
static int list_length(const List *l)
Definition: pg_list.h:89
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4410
#define AccessExclusiveLock
Definition: lockdefs.h:45
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:167
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:4553
void * palloc(Size size)
Definition: mcxt.c:835
int errmsg(const char *fmt,...)
Definition: elog.c:797
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:139
void ResetSequence(Oid seq_relid)
Definition: sequence.c:269
bool reindex_relation(Oid relid, int flags, int options)
Definition: index.c:3793
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:425
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3032
#define lfirst_oid(lc)
Definition: pg_list.h:108
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:457

◆ find_composite_type_dependencies()

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

Definition at line 5014 of file tablecmds.c.

References AccessShareLock, Anum_pg_depend_refclassid, Anum_pg_depend_refobjid, BTEqualStrategyNumber, check_stack_depth(), DependReferenceIndexId, DependRelationId, ereport, errcode(), errmsg(), ERROR, find_composite_type_dependencies(), GETSTRUCT, heap_open(), HeapTupleIsValid, NameStr, ObjectIdGetDatum, OidIsValid, RelationData::rd_att, RelationData::rd_rel, relation_close(), relation_open(), RelationGetRelationName, RelationRelationId, RELKIND_COMPOSITE_TYPE, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), TupleDescAttr, and TypeRelationId.

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

5016 {
5017  Relation depRel;
5018  ScanKeyData key[2];
5019  SysScanDesc depScan;
5020  HeapTuple depTup;
5021 
5022  /* since this function recurses, it could be driven to stack overflow */
5024 
5025  /*
5026  * We scan pg_depend to find those things that depend on the given type.
5027  * (We assume we can ignore refobjsubid for a type.)
5028  */
5030 
5031  ScanKeyInit(&key[0],
5033  BTEqualStrategyNumber, F_OIDEQ,
5035  ScanKeyInit(&key[1],
5037  BTEqualStrategyNumber, F_OIDEQ,
5038  ObjectIdGetDatum(typeOid));
5039 
5040  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
5041  NULL, 2, key);
5042 
5043  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
5044  {
5045  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
5046  Relation rel;
5047  Form_pg_attribute att;
5048 
5049  /* Check for directly dependent types */
5050  if (pg_depend->classid == TypeRelationId)
5051  {
5052  /*
5053  * This must be an array, domain, or range containing the given
5054  * type, so recursively check for uses of this type. Note that
5055  * any error message will mention the original type not the
5056  * container; this is intentional.
5057  */
5058  find_composite_type_dependencies(pg_depend->objid,
5059  origRelation, origTypeName);
5060  continue;
5061  }
5062 
5063  /* Else, ignore dependees that aren't user columns of relations */
5064  /* (we assume system columns are never of interesting types) */
5065  if (pg_depend->classid != RelationRelationId ||
5066  pg_depend->objsubid <= 0)
5067  continue;
5068 
5069  rel = relation_open(pg_depend->objid, AccessShareLock);
5070  att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
5071 
5072  if (rel->rd_rel->relkind == RELKIND_RELATION ||
5073  rel->rd_rel->relkind == RELKIND_MATVIEW ||
5074  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5075  {
5076  if (origTypeName)
5077  ereport(ERROR,
5078  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5079  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5080  origTypeName,
5082  NameStr(att->attname))));
5083  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
5084  ereport(ERROR,
5085  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5086  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5087  RelationGetRelationName(origRelation),
5089  NameStr(att->attname))));
5090  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
5091  ereport(ERROR,
5092  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5093  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
5094  RelationGetRelationName(origRelation),
5096  NameStr(att->attname))));
5097  else
5098  ereport(ERROR,
5099  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5100  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
5101  RelationGetRelationName(origRelation),
5103  NameStr(att->attname))));
5104  }
5105  else if (OidIsValid(rel->rd_rel->reltype))
5106  {
5107  /*
5108  * A view or composite type itself isn't a problem, but we must
5109  * recursively check for indirect dependencies via its rowtype.
5110  */
5112  origRelation, origTypeName);
5113  }
5114 
5116  }
5117 
5118  systable_endscan(depScan);
5119 
5121 }
#define Anum_pg_depend_refobjid
Definition: pg_depend.h:72
#define Anum_pg_depend_refclassid
Definition: pg_depend.h:71
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
#define RelationRelationId
Definition: pg_class.h:29
#define DependReferenceIndexId
Definition: indexing.h:147
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:5014
#define DependRelationId
Definition: pg_depend.h:29
#define RELKIND_MATVIEW
Definition: pg_class.h:165
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
Form_pg_class rd_rel
Definition: rel.h:114
#define TypeRelationId
Definition: pg_type.h:34
#define OidIsValid(objectId)
Definition: c.h:594
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
#define RELKIND_COMPOSITE_TYPE
Definition: pg_class.h:166
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
void check_stack_depth(void)
Definition: postgres.c:3154
#define RelationGetRelationName(relation)
Definition: rel.h:445
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:61
#define ereport(elevel, rest)
Definition: elog.h:122
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
TupleDesc rd_att
Definition: rel.h:115
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:565
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120
#define RELKIND_RELATION
Definition: pg_class.h:160
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ PartConstraintImpliedByRelConstraint()

bool PartConstraintImpliedByRelConstraint ( Relation  scanrel,
List partConstraint 
)

Definition at line 13660 of file tablecmds.c.

References NullTest::arg, NullTest::argisrow, canonicalize_qual(), constrCheck::ccbin, constrCheck::ccvalid, tupleConstr::check, eval_const_expressions(), tupleConstr::has_not_null, i, IS_NOT_NULL, lappend(), list_concat(), list_make1, NullTest::location, make_ands_explicit(), make_ands_implicit(), makeNode, makeVar(), tupleDesc::natts, NIL, NullTest::nulltesttype, tupleConstr::num_check, predicate_implied_by(), RelationData::rd_att, RelationGetDescr, stringToNode(), and TupleDescAttr.

Referenced by check_default_allows_bound(), and ValidatePartitionConstraints().

13662 {
13663  List *existConstraint = NIL;
13664  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
13665  int num_check,
13666  i;
13667 
13668  if (constr && constr->has_not_null)
13669  {
13670  int natts = scanrel->rd_att->natts;
13671 
13672  for (i = 1; i <= natts; i++)
13673  {
13674  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
13675 
13676  if (att->attnotnull && !att->attisdropped)
13677  {
13678  NullTest *ntest = makeNode(NullTest);
13679 
13680  ntest->arg = (Expr *) makeVar(1,
13681  i,
13682  att->atttypid,
13683  att->atttypmod,
13684  att->attcollation,
13685  0);
13686  ntest->nulltesttype = IS_NOT_NULL;
13687 
13688  /*
13689  * argisrow=false is correct even for a composite column,
13690  * because attnotnull does not represent a SQL-spec IS NOT
13691  * NULL test in such a case, just IS DISTINCT FROM NULL.
13692  */
13693  ntest->argisrow = false;
13694  ntest->location = -1;
13695  existConstraint = lappend(existConstraint, ntest);
13696  }
13697  }
13698  }
13699 
13700  num_check = (constr != NULL) ? constr->num_check : 0;
13701  for (i = 0; i < num_check; i++)
13702  {
13703  Node *cexpr;
13704 
13705  /*
13706  * If this constraint hasn't been fully validated yet, we must ignore
13707  * it here.
13708  */
13709  if (!constr->check[i].ccvalid)
13710  continue;
13711 
13712  cexpr = stringToNode(constr->check[i].ccbin);
13713 
13714  /*
13715  * Run each expression through const-simplification and
13716  * canonicalization. It is necessary, because we will be comparing it
13717  * to similarly-processed partition constraint expressions, and may
13718  * fail to detect valid matches without this.
13719  */
13720  cexpr = eval_const_expressions(NULL, cexpr);
13721  cexpr = (Node *) canonicalize_qual((Expr *) cexpr);
13722 
13723  existConstraint = list_concat(existConstraint,
13724  make_ands_implicit((Expr *) cexpr));
13725  }
13726 
13727  if (existConstraint != NIL)
13728  existConstraint = list_make1(make_ands_explicit(existConstraint));
13729 
13730  /* And away we go ... */
13731  return predicate_implied_by(partConstraint, existConstraint, true);
13732 }
#define NIL
Definition: pg_list.h:69
bool predicate_implied_by(List *predicate_list, List *clause_list, bool clause_is_check)
Definition: predtest.c:135
void * stringToNode(char *str)
Definition: read.c:38
#define RelationGetDescr(relation)
Definition: rel.h:437
ConstrCheck * check
Definition: tupdesc.h:40
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
char * ccbin
Definition: tupdesc.h:31
Definition: nodes.h:513
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2462
List * list_concat(List *list1, List *list2)
Definition: list.c:321
int natts
Definition: tupdesc.h:79
Expr * make_ands_explicit(List *andclauses)
Definition: clauses.c:370
#define list_make1(x1)
Definition: pg_list.h:139
List * make_ands_implicit(Expr *clause)
Definition: clauses.c:381
Expr * arg
Definition: primnodes.h:1187
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
bool has_not_null
Definition: tupdesc.h:43
List * lappend(List *list, void *datum)
Definition: list.c:128
Expr * canonicalize_qual(Expr *qual)
Definition: prepqual.c:286
TupleDesc rd_att
Definition: rel.h:115
NullTestType nulltesttype
Definition: primnodes.h:1188
#define makeNode(_type_)
Definition: nodes.h:561
int location
Definition: primnodes.h:1190
bool ccvalid
Definition: tupdesc.h:32
int i
bool argisrow
Definition: primnodes.h:1189
uint16 num_check
Definition: tupdesc.h:42
Definition: pg_list.h:45

◆ PreCommit_on_commit_actions()

void PreCommit_on_commit_actions ( void  )

Definition at line 13011 of file tablecmds.c.

References Assert, ObjectAddress::classId, CommandCounterIncrement(), OnCommitItem::deleting_subid, DROP_CASCADE, heap_truncate(), InvalidSubTransactionId, lappend_oid(), lfirst, MyXactFlags, NIL, OnCommitItem::oncommit, ONCOMMIT_DELETE_ROWS, ONCOMMIT_DROP, ONCOMMIT_NOOP, ONCOMMIT_PRESERVE_ROWS, PERFORM_DELETION_INTERNAL, performDeletion(), RelationRelationId, OnCommitItem::relid, and XACT_FLAGS_ACCESSEDTEMPREL.

Referenced by CommitTransaction(), and PrepareTransaction().

13012 {
13013  ListCell *l;
13014  List *oids_to_truncate = NIL;
13015 
13016  foreach(l, on_commits)
13017  {
13018  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
13019 
13020  /* Ignore entry if already dropped in this xact */
13022  continue;
13023 
13024  switch (oc->oncommit)
13025  {
13026  case ONCOMMIT_NOOP:
13028  /* Do nothing (there shouldn't be such entries, actually) */
13029  break;
13030  case ONCOMMIT_DELETE_ROWS:
13031 
13032  /*
13033  * If this transaction hasn't accessed any temporary
13034  * relations, we can skip truncating ON COMMIT DELETE ROWS
13035  * tables, as they must still be empty.
13036  */
13038  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
13039  break;
13040  case ONCOMMIT_DROP:
13041  {
13042  ObjectAddress object;
13043 
13044  object.classId = RelationRelationId;
13045  object.objectId = oc->relid;
13046  object.objectSubId = 0;
13047 
13048  /*
13049  * Since this is an automatic drop, rather than one
13050  * directly initiated by the user, we pass the
13051  * PERFORM_DELETION_INTERNAL flag.
13052  */
13053  performDeletion(&object,
13055 
13056  /*
13057  * Note that table deletion will call
13058  * remove_on_commit_action, so the entry should get marked
13059  * as deleted.
13060  */
13062  break;
13063  }
13064  }
13065  }
13066  if (oids_to_truncate != NIL)
13067  {
13068  heap_truncate(oids_to_truncate);
13069  CommandCounterIncrement(); /* XXX needed? */
13070  }
13071 }
#define NIL
Definition: pg_list.h:69
OnCommitAction oncommit
Definition: tablecmds.c:111
#define RelationRelationId
Definition: pg_class.h:29
#define XACT_FLAGS_ACCESSEDTEMPREL
Definition: xact.h:86
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
static List * on_commits
Definition: tablecmds.c:124
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:303
int MyXactFlags
Definition: xact.c:118
SubTransactionId deleting_subid
Definition: tablecmds.c:121
void CommandCounterIncrement(void)
Definition: xact.c:915
#define Assert(condition)
Definition: c.h:688
#define lfirst(lc)
Definition: pg_list.h:106
void heap_truncate(List *relids)
Definition: heap.c:2862
#define InvalidSubTransactionId
Definition: c.h:469
Definition: pg_list.h:45
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:189

◆ RangeVarCallbackOwnsRelation()

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

Definition at line 13202 of file tablecmds.c.

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

Referenced by AlterSequence(), and ProcessUtilitySlow().

13204 {
13205  HeapTuple tuple;
13206 
13207  /* Nothing to do if the relation was not found. */
13208  if (!OidIsValid(relId))
13209  return;
13210 
13211  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
13212  if (!HeapTupleIsValid(tuple)) /* should not happen */
13213  elog(ERROR, "cache lookup failed for relation %u", relId);
13214 
13215  if (!pg_class_ownercheck(relId, GetUserId()))
13217  relation->relname);
13218 
13219  if (!allowSystemTableMods &&
13220  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
13221  ereport(ERROR,
13222  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
13223  errmsg("permission denied: \"%s\" is a system catalog",
13224  relation->relname)));
13225 
13226  ReleaseSysCache(tuple);
13227 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
Oid GetUserId(void)
Definition: miscinit.c:284
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
int errcode(int sqlerrcode)
Definition: elog.c:575
#define OidIsValid(objectId)
Definition: c.h:594
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:75
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
bool allowSystemTableMods
Definition: globals.c:112
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4752
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
int errmsg(const char *fmt,...)
Definition: elog.c:797
ObjectType get_relkind_objtype(char relkind)
#define elog
Definition: elog.h:219

◆ RangeVarCallbackOwnsTable()

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

Definition at line 13169 of file tablecmds.c.

References aclcheck_error(), ACLCHECK_NOT_OWNER, ereport, errcode(), errmsg(), ERROR, get_rel_relkind(), get_relkind_objtype(), GetUserId(), OidIsValid, pg_class_ownercheck(), DropRelationCallbackState::relkind, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RELKIND_TOASTVALUE, and RangeVar::relname.

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

13171 {
13172  char relkind;
13173 
13174  /* Nothing to do if the relation was not found. */
13175  if (!OidIsValid(relId))
13176  return;
13177 
13178  /*
13179  * If the relation does exist, check whether it's an index. But note that
13180  * the relation might have been dropped between the time we did the name
13181  * lookup and now. In that case, there's nothing to do.
13182  */
13183  relkind = get_rel_relkind(relId);
13184  if (!relkind)
13185  return;
13186  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
13187  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
13188  ereport(ERROR,
13189  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13190  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
13191 
13192  /* Check permissions */
13193  if (!pg_class_ownercheck(relId, GetUserId()))
13195 }
Oid GetUserId(void)
Definition: miscinit.c:284
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
#define RELKIND_MATVIEW
Definition: pg_class.h:165
int errcode(int sqlerrcode)
Definition: elog.c:575
#define OidIsValid(objectId)
Definition: c.h:594
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define RELKIND_TOASTVALUE
Definition: pg_class.h:163
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4752
int errmsg(const char *fmt,...)
Definition: elog.c:797
ObjectType get_relkind_objtype(char relkind)
#define RELKIND_RELATION
Definition: pg_class.h:160

◆ register_on_commit_action()

void register_on_commit_action ( Oid  relid,
OnCommitAction  action 
)

Definition at line 12957 of file tablecmds.c.

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

Referenced by heap_create_with_catalog().

12958 {
12959  OnCommitItem *oc;
12960  MemoryContext oldcxt;
12961 
12962  /*
12963  * We needn't bother registering the relation unless there is an ON COMMIT
12964  * action we need to take.
12965  */
12967  return;
12968 
12970 
12971  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
12972  oc->relid = relid;
12973  oc->oncommit = action;
12976 
12977  on_commits = lcons(oc, on_commits);
12978 
12979  MemoryContextSwitchTo(oldcxt);
12980 }
OnCommitAction oncommit
Definition: tablecmds.c:111
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
SubTransactionId creating_subid
Definition: tablecmds.c:120
static List * on_commits
Definition: tablecmds.c:124
SubTransactionId deleting_subid
Definition: tablecmds.c:121
List * lcons(void *datum, List *list)
Definition: list.c:259
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:642
#define InvalidSubTransactionId
Definition: c.h:469
void * palloc(Size size)
Definition: mcxt.c:835
MemoryContext CacheMemoryContext
Definition: mcxt.c:46

◆ remove_on_commit_action()

void remove_on_commit_action ( Oid  relid)

Definition at line 12988 of file tablecmds.c.

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

Referenced by heap_drop_with_catalog().

12989 {
12990  ListCell *l;
12991 
12992  foreach(l, on_commits)
12993  {
12994  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
12995 
12996  if (oc->relid == relid)
12997  {
12999  break;
13000  }
13001  }
13002 }
static List * on_commits
Definition: tablecmds.c:124
SubTransactionId deleting_subid
Definition: tablecmds.c:121
#define lfirst(lc)
Definition: pg_list.h:106
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:642

◆ RemoveRelations()

void RemoveRelations ( DropStmt drop)

Definition at line 1069 of file tablecmds.c.

References AcceptInvalidationMessages(), AccessExclusiveLock, add_exact_object_address(), Assert, DropStmt::behavior, ObjectAddress::classId, DropRelationCallbackState::concurrent, DropStmt::concurrent, DROP_CASCADE, DropErrorMsgNonExistent(), elog, ereport, errcode(), errmsg(), ERROR, free_object_addresses(), DropRelationCallbackState::heapOid, InvalidOid, lfirst, list_length(), makeRangeVarFromNameList(), DropStmt::missing_ok, new_object_addresses(), OBJECT_FOREIGN_TABLE, OBJECT_INDEX, OBJECT_MATVIEW, OBJECT_SEQUENCE, OBJECT_TABLE, OBJECT_VIEW, ObjectAddress::objectId, DropStmt::objects, ObjectAddress::objectSubId, OidIsValid, DropRelationCallbackState::partParentOid, PERFORM_DELETION_CONCURRENTLY, performMultipleDeletions(), RangeVarCallbackForDropRelation(), RangeVarGetRelidExtended(), RelationRelationId, DropRelationCallbackState::relkind, RELKIND_FOREIGN_TABLE, RELKIND_INDEX, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, DropStmt::removeType, and ShareUpdateExclusiveLock.

Referenced by ExecDropStmt().

1070 {
1071  ObjectAddresses *objects;
1072  char relkind;
1073  ListCell *cell;
1074  int flags = 0;
1075  LOCKMODE lockmode = AccessExclusiveLock;
1076 
1077  /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1078  if (drop->concurrent)
1079  {
1081  lockmode = ShareUpdateExclusiveLock;
1082  Assert(drop->removeType == OBJECT_INDEX);
1083  if (list_length(drop->objects) != 1)
1084  ereport(ERROR,
1085  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1086  errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1087  if (drop->behavior == DROP_CASCADE)
1088  ereport(ERROR,
1089  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1090  errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1091  }
1092 
1093  /*
1094  * First we identify all the relations, then we delete them in a single
1095  * performMultipleDeletions() call. This is to avoid unwanted DROP
1096  * RESTRICT errors if one of the relations depends on another.
1097  */
1098 
1099  /* Determine required relkind */
1100  switch (drop->removeType)
1101  {
1102  case OBJECT_TABLE:
1103  relkind = RELKIND_RELATION;
1104  break;
1105 
1106  case OBJECT_INDEX:
1107  relkind = RELKIND_INDEX;
1108  break;
1109 
1110  case OBJECT_SEQUENCE:
1111  relkind = RELKIND_SEQUENCE;
1112  break;
1113 
1114  case OBJECT_VIEW:
1115  relkind = RELKIND_VIEW;
1116  break;
1117 
1118  case OBJECT_MATVIEW:
1119  relkind = RELKIND_MATVIEW;
1120  break;
1121 
1122  case OBJECT_FOREIGN_TABLE:
1123  relkind = RELKIND_FOREIGN_TABLE;
1124  break;
1125 
1126  default:
1127  elog(ERROR, "unrecognized drop object type: %d",
1128  (int) drop->removeType);
1129  relkind = 0; /* keep compiler quiet */
1130  break;
1131  }
1132 
1133  /* Lock and validate each relation; build a list of object addresses */
1134  objects = new_object_addresses();
1135 
1136  foreach(cell, drop->objects)
1137  {
1138  RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1139  Oid relOid;
1140  ObjectAddress obj;
1142 
1143  /*
1144  * These next few steps are a great deal like relation_openrv, but we
1145  * don't bother building a relcache entry since we don't need it.
1146  *
1147  * Check for shared-cache-inval messages before trying to access the
1148  * relation. This is needed to cover the case where the name
1149  * identifies a rel that has been dropped and recreated since the
1150  * start of our transaction: if we don't flush the old syscache entry,
1151  * then we'll latch onto that entry and suffer an error later.
1152  */
1154 
1155  /* Look up the appropriate relation using namespace search. */
1156  state.relkind = relkind;
1157  state.heapOid = InvalidOid;
1158  state.partParentOid = InvalidOid;
1159  state.concurrent = drop->concurrent;
1160  relOid = RangeVarGetRelidExtended(rel, lockmode, true,
1161  false,
1163  (void *) &state);
1164 
1165  /* Not there? */
1166  if (!OidIsValid(relOid))
1167  {
1168  DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1169  continue;
1170  }
1171 
1172  /* OK, we're ready to delete this one */
1174  obj.objectId = relOid;
1175  obj.objectSubId = 0;
1176 
1177  add_exact_object_address(&obj, objects);
1178  }
1179 
1180  performMultipleDeletions(objects, drop->behavior, flags);
1181 
1182  free_object_addresses(objects);
1183 }
void AcceptInvalidationMessages(void)
Definition: inval.c:679
int LOCKMODE
Definition: lockdefs.h:26
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:218
#define RelationRelationId
Definition: pg_class.h:29
List * objects
Definition: parsenodes.h:2586
bool missing_ok
Definition: parsenodes.h:2589
#define RELKIND_MATVIEW
Definition: pg_class.h:165
int errcode(int sqlerrcode)
Definition: elog.c:575
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3023
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2188
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2133
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2404
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:594
ObjectType removeType
Definition: parsenodes.h:2587
#define PERFORM_DELETION_CONCURRENTLY
Definition: dependency.h:190
#define ERROR
Definition: elog.h:43
bool concurrent
Definition: parsenodes.h:2590
DropBehavior behavior
Definition: parsenodes.h:2588
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
#define ereport(elevel, rest)
Definition: elog.h:122
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:1192
#define InvalidOid
Definition: postgres_ext.h:36
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define Assert(condition)
Definition: c.h:688
#define lfirst(lc)
Definition: pg_list.h:106
Definition: regguts.h:298
static int list_length(const List *l)
Definition: pg_list.h:89
#define AccessExclusiveLock
Definition: lockdefs.h:45
static void DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
Definition: tablecmds.c:994
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define RELKIND_VIEW
Definition: pg_class.h:164
#define RELKIND_INDEX
Definition: pg_class.h:161
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:362
#define elog
Definition: elog.h:219
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RELKIND_SEQUENCE
Definition: pg_class.h:162
Definition: pg_list.h:45

◆ renameatt()

ObjectAddress renameatt ( RenameStmt stmt)

Definition at line 2786 of file tablecmds.c.

References AccessExclusiveLock, RenameStmt::behavior, ereport, errmsg(), RangeVar::inh, InvalidObjectAddress, RenameStmt::missing_ok, RenameStmt::newname, NOTICE, ObjectAddressSubSet, OidIsValid, RangeVarCallbackForRenameAttribute(), RangeVarGetRelidExtended(), RenameStmt::relation, RelationRelationId, OnCommitItem::relid, RangeVar::relname, renameatt_internal(), and RenameStmt::subname.

Referenced by ExecRenameStmt().

2787 {
2788  Oid relid;
2789  AttrNumber attnum;
2790  ObjectAddress address;
2791 
2792  /* lock level taken here should match renameatt_internal */
2794  stmt->missing_ok, false,
2796  NULL);
2797 
2798  if (!OidIsValid(relid))
2799  {
2800  ereport(NOTICE,
2801  (errmsg("relation \"%s\" does not exist, skipping",
2802  stmt->relation->relname)));
2803  return InvalidObjectAddress;
2804  }
2805 
2806  attnum =
2807  renameatt_internal(relid,
2808  stmt->subname, /* old att name */
2809  stmt->newname, /* new att name */
2810  stmt->relation->inh, /* recursive? */
2811  false, /* recursing? */
2812  0, /* expected inhcount */
2813  stmt->behavior);
2814 
2815  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
2816 
2817  return address;
2818 }
char * subname
Definition: parsenodes.h:2838
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:218
#define RelationRelationId
Definition: pg_class.h:29
char * newname
Definition: parsenodes.h:2840
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:594
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2842
#define ereport(elevel, rest)
Definition: elog.h:122
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:2836
#define NOTICE
Definition: elog.h:37
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:2766
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:2621
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
DropBehavior behavior
Definition: parsenodes.h:2841
int16 AttrNumber
Definition: attnum.h:21

◆ renameatt_type()

ObjectAddress renameatt_type ( RenameStmt stmt)

◆ RenameConstraint()

ObjectAddress RenameConstraint ( RenameStmt stmt)

Definition at line 2923 of file tablecmds.c.

References AccessExclusiveLock, castNode, checkDomainOwner(), elog, ereport, errmsg(), ERROR, heap_close, heap_open(), HeapTupleIsValid, RangeVar::inh, InvalidObjectAddress, InvalidOid, makeTypeNameFromNameList(), RenameStmt::missing_ok, RenameStmt::newname, NoLock, NOTICE, RenameStmt::object, OBJECT_DOMCONSTRAINT, ObjectIdGetDatum, OidIsValid, RangeVarCallbackForRenameAttribute(), RangeVarGetRelidExtended(), RenameStmt::relation, ReleaseSysCache(), OnCommitItem::relid, RangeVar::relname, rename_constraint_internal(), RenameStmt::renameType, RowExclusiveLock, SearchSysCache1(), RenameStmt::subname, typenameTypeId(), TYPEOID, and TypeRelationId.

Referenced by ExecRenameStmt().

2924 {
2925  Oid relid = InvalidOid;
2926  Oid typid = InvalidOid;
2927 
2928  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
2929  {
2930  Relation rel;
2931  HeapTuple tup;
2932 
2935  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2936  if (!HeapTupleIsValid(tup))
2937  elog(ERROR, "cache lookup failed for type %u", typid);
2938  checkDomainOwner(tup);
2939  ReleaseSysCache(tup);
2940  heap_close(rel, NoLock);
2941  }
2942  else
2943  {
2944  /* lock level taken here should match rename_constraint_internal */
2946  stmt->missing_ok, false,
2948  NULL);
2949  if (!OidIsValid(relid))
2950  {
2951  ereport(NOTICE,
2952  (errmsg("relation \"%s\" does not exist, skipping",
2953  stmt->relation->relname)));
2954  return InvalidObjectAddress;
2955  }
2956  }
2957 
2958  return
2959  rename_constraint_internal(relid, typid,
2960  stmt->subname,
2961  stmt->newname,
2962  (stmt->relation &&
2963  stmt->relation->inh), /* recursive? */
2964  false, /* recursing? */
2965  0 /* expected inhcount */ );
2966 
2967 }
char * subname
Definition: parsenodes.h:2838
ObjectType renameType
Definition: parsenodes.h:2834
#define castNode(_type_, nodeptr)
Definition: nodes.h:582
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:218
#define heap_close(r, l)
Definition: heapam.h:97
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:2824
char * newname
Definition: parsenodes.h:2840
unsigned int Oid
Definition: postgres_ext.h:31
#define TypeRelationId
Definition: pg_type.h:34
#define OidIsValid(objectId)
Definition: c.h:594
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2842
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Node * object
Definition: parsenodes.h:2837
#define ereport(elevel, rest)
Definition: elog.h:122
bool inh
Definition: primnodes.h:69
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
RangeVar * relation
Definition: parsenodes.h:2836
#define InvalidOid
Definition: postgres_ext.h:36
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:2766
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3041
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:455
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274

◆ RenameRelation()

ObjectAddress RenameRelation ( RenameStmt stmt)

Definition at line 2974 of file tablecmds.c.

References AccessExclusiveLock, ereport, errmsg(), InvalidObjectAddress, RenameStmt::missing_ok, NOTICE, ObjectAddressSet, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetRelidExtended(), RenameStmt::relation, RelationRelationId, OnCommitItem::relid, and RenameRelationInternal().

Referenced by ExecRenameStmt().

2975 {
2976  Oid relid;
2977  ObjectAddress address;
2978 
2979  /*
2980  * Grab an exclusive lock on the target table, index, sequence, view,
2981  * materialized view, or foreign table, which we will NOT release until
2982  * end of transaction.
2983  *
2984  * Lock level used here should match RenameRelationInternal, to avoid lock
2985  * escalation.
2986  */
2988  stmt->missing_ok, false,
2990  (void *) stmt);
2991 
2992  if (!OidIsValid(relid))
2993  {
2994  ereport(NOTICE,
2995  (errmsg("relation \"%s\" does not exist, skipping",
2996  stmt->relation->relname)));
2997  return InvalidObjectAddress;
2998  }
2999 
3000  /* Do the work */
3001  RenameRelationInternal(relid, stmt->newname, false);
3002 
3003  ObjectAddressSet(address, RelationRelationId, relid);
3004 
3005  return address;
3006 }
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
Definition: tablecmds.c:3018
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:218
#define RelationRelationId
Definition: pg_class.h:29
char * newname
Definition: parsenodes.h:2840
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:594
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2842
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:13234
#define ereport(elevel, rest)
Definition: elog.h:122
RangeVar * relation
Definition: parsenodes.h:2836
#define NOTICE
Definition: elog.h:37
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ RenameRelationInternal()

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

Definition at line 3018 of file tablecmds.c.

References AccessExclusiveLock, CatalogTupleUpdate(), elog, ereport, errcode(), errmsg(), ERROR, get_index_constraint(), get_relname_relid(), GETSTRUCT, heap_close, heap_freetuple(), heap_open(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHookArg, namestrcpy(), NoLock, ObjectIdGetDatum, OidIsValid, RelationData::rd_rel, relation_close(), relation_open(), RelationGetNamespace, RelationRelationId, RELKIND_INDEX, RELKIND_PARTITIONED_INDEX, RELOID, RenameConstraintById(), RenameTypeInternal(), RowExclusiveLock, SearchSysCacheCopy1, and HeapTupleData::t_self.

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

3019 {
3020  Relation targetrelation;
3021  Relation relrelation; /* for RELATION relation */
3022  HeapTuple reltup;
3023  Form_pg_class relform;
3024  Oid namespaceId;
3025 
3026  /*
3027  * Grab an exclusive lock on the target table, index, sequence, view,
3028  * materialized view, or foreign table, which we will NOT release until
3029  * end of transaction.
3030  */
3031  targetrelation = relation_open(myrelid, AccessExclusiveLock);
3032  namespaceId = RelationGetNamespace(targetrelation);
3033 
3034  /*
3035  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3036  */
3038 
3039  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3040  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3041  elog(ERROR, "cache lookup failed for relation %u", myrelid);
3042  relform = (Form_pg_class) GETSTRUCT(reltup);
3043 
3044  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3045  ereport(ERROR,
3046  (errcode(ERRCODE_DUPLICATE_TABLE),
3047  errmsg("relation \"%s\" already exists",
3048  newrelname)));
3049 
3050  /*
3051  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
3052  * because it's a copy...)
3053  */
3054  namestrcpy(&(relform->relname), newrelname);
3055 
3056  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3057 
3059  InvalidOid, is_internal);
3060 
3061  heap_freetuple(reltup);
3062  heap_close(relrelation, RowExclusiveLock);
3063 
3064  /*
3065  * Also rename the associated type, if any.
3066  */
3067  if (OidIsValid(targetrelation->rd_rel->reltype))
3068  RenameTypeInternal(targetrelation->rd_rel->reltype,
3069  newrelname, namespaceId);
3070 
3071  /*
3072  * Also rename the associated constraint, if any.
3073  */
3074  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3075  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3076  {
3077  Oid constraintId = get_index_constraint(myrelid);
3078 
3079  if (OidIsValid(constraintId))
3080  RenameConstraintById(constraintId, newrelname);
3081  }
3082 
3083  /*
3084  * Close rel, but keep exclusive lock!
3085  */
3086  relation_close(targetrelation, NoLock);
3087 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define RelationRelationId
Definition: pg_class.h:29
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:216
#define OidIsValid(objectId)
Definition: c.h:594
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
Definition: objectaccess.h:166
void RenameConstraintById(Oid conId, const char *newname)
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1687
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:689
#define ereport(elevel, rest)
Definition: elog.h:122
#define RELKIND_PARTITIONED_INDEX
Definition: pg_class.h:169
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:692
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define RELKIND_INDEX
Definition: pg_class.h:161
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120
#define elog
Definition: elog.h:219
#define RelationGetNamespace(relation)
Definition: rel.h:452

◆ SetRelationHasSubclass()

void SetRelationHasSubclass ( Oid  relationId,
bool  relhassubclass 
)

Definition at line 2539 of file tablecmds.c.

References CacheInvalidateRelcacheByTuple(), CatalogTupleUpdate(), elog, ERROR, GETSTRUCT, heap_close, heap_freetuple(), heap_open(), HeapTupleIsValid, ObjectIdGetDatum, RelationRelationId, RELOID, RowExclusiveLock, SearchSysCacheCopy1, and HeapTupleData::t_self.

Referenced by acquire_inherited_sample_rows(), and StoreCatalogInheritance1().

2540 {
2541  Relation relationRelation;
2542  HeapTuple tuple;
2543  Form_pg_class classtuple;
2544 
2545  /*
2546  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
2547  */
2548  relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
2549  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
2550  if (!HeapTupleIsValid(tuple))
2551  elog(ERROR, "cache lookup failed for relation %u", relationId);
2552  classtuple = (Form_pg_class) GETSTRUCT(tuple);
2553 
2554  if (classtuple->relhassubclass != relhassubclass)
2555  {
2556  classtuple->relhassubclass = relhassubclass;
2557  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
2558  }
2559  else
2560  {
2561  /* no need to change tuple, but force relcache rebuild anyway */
2563  }
2564 
2565  heap_freetuple(tuple);
2566  heap_close(relationRelation, RowExclusiveLock);
2567 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define RelationRelationId
Definition: pg_class.h:29
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1269
#define elog
Definition: elog.h:219