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

Go to the source code of this file.

Functions

ObjectAddress DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
 
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 ExecuteTruncateGuts (List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs)
 
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 createForeignKeyTriggers (Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, bool create_action)
 
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 12975 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, NameStr, object_address_present(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, RELOID, SearchSysCacheCopy1, and HeapTupleData::t_self.

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

12979 {
12980  HeapTuple classTup;
12981  Form_pg_class classForm;
12982  ObjectAddress thisobj;
12983  bool already_done = false;
12984 
12985  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
12986  if (!HeapTupleIsValid(classTup))
12987  elog(ERROR, "cache lookup failed for relation %u", relOid);
12988  classForm = (Form_pg_class) GETSTRUCT(classTup);
12989 
12990  Assert(classForm->relnamespace == oldNspOid);
12991 
12992  thisobj.classId = RelationRelationId;
12993  thisobj.objectId = relOid;
12994  thisobj.objectSubId = 0;
12995 
12996  /*
12997  * If the object has already been moved, don't move it again. If it's
12998  * already in the right place, don't move it, but still fire the object
12999  * access hook.
13000  */
13001  already_done = object_address_present(&thisobj, objsMoved);
13002  if (!already_done && oldNspOid != newNspOid)
13003  {
13004  /* check for duplicate name (more friendly than unique-index failure) */
13005  if (get_relname_relid(NameStr(classForm->relname),
13006  newNspOid) != InvalidOid)
13007  ereport(ERROR,
13008  (errcode(ERRCODE_DUPLICATE_TABLE),
13009  errmsg("relation \"%s\" already exists in schema \"%s\"",
13010  NameStr(classForm->relname),
13011  get_namespace_name(newNspOid))));
13012 
13013  /* classTup is a copy, so OK to scribble on */
13014  classForm->relnamespace = newNspOid;
13015 
13016  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
13017 
13018  /* Update dependency on schema if caller said so */
13019  if (hasDependEntry &&
13020  changeDependencyFor(RelationRelationId,
13021  relOid,
13022  NamespaceRelationId,
13023  oldNspOid,
13024  newNspOid) != 1)
13025  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
13026  NameStr(classForm->relname));
13027  }
13028  if (!already_done)
13029  {
13030  add_exact_object_address(&thisobj, objsMoved);
13031 
13032  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
13033  }
13034 
13035  heap_freetuple(classTup);
13036 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2245
int errcode(int sqlerrcode)
Definition: elog.c:575
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2185
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#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:78
#define Assert(condition)
Definition: c.h:699
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
FormData_pg_class * Form_pg_class
Definition: pg_class.h:93
#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:576
#define elog
Definition: elog.h:219

◆ AlterTable()

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

Definition at line 3303 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3304 {
3305  Relation rel;
3306 
3307  /* Caller is required to provide an adequate lock. */
3308  rel = relation_open(relid, NoLock);
3309 
3310  CheckTableNotInUse(rel, "ALTER TABLE");
3311 
3312  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode);
3313 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3621
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3222
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1718
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1124

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 3372 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().

3373 {
3374  /*
3375  * This only works if we read catalog tables using MVCC snapshots.
3376  */
3377  ListCell *lcmd;
3379 
3380  foreach(lcmd, cmds)
3381  {
3382  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3383  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
3384 
3385  switch (cmd->subtype)
3386  {
3387  /*
3388  * These subcommands rewrite the heap, so require full locks.
3389  */
3390  case AT_AddColumn: /* may rewrite heap, in some cases and visible
3391  * to SELECT */
3392  case AT_SetTableSpace: /* must rewrite heap */
3393  case AT_AlterColumnType: /* must rewrite heap */
3394  case AT_AddOids: /* must rewrite heap */
3395  cmd_lockmode = AccessExclusiveLock;
3396  break;
3397 
3398  /*
3399  * These subcommands may require addition of toast tables. If
3400  * we add a toast table to a table currently being scanned, we
3401  * might miss data added to the new toast table by concurrent
3402  * insert transactions.
3403  */
3404  case AT_SetStorage: /* may add toast tables, see
3405  * ATRewriteCatalogs() */
3406  cmd_lockmode = AccessExclusiveLock;
3407  break;
3408 
3409  /*
3410  * Removing constraints can affect SELECTs that have been
3411  * optimised assuming the constraint holds true.
3412  */
3413  case AT_DropConstraint: /* as DROP INDEX */
3414  case AT_DropNotNull: /* may change some SQL plans */
3415  cmd_lockmode = AccessExclusiveLock;
3416  break;
3417 
3418  /*
3419  * Subcommands that may be visible to concurrent SELECTs
3420  */
3421  case AT_DropColumn: /* change visible to SELECT */
3422  case AT_AddColumnToView: /* CREATE VIEW */
3423  case AT_DropOids: /* calls AT_DropColumn */
3424  case AT_EnableAlwaysRule: /* may change SELECT rules */
3425  case AT_EnableReplicaRule: /* may change SELECT rules */
3426  case AT_EnableRule: /* may change SELECT rules */
3427  case AT_DisableRule: /* may change SELECT rules */
3428  cmd_lockmode = AccessExclusiveLock;
3429  break;
3430 
3431  /*
3432  * Changing owner may remove implicit SELECT privileges
3433  */
3434  case AT_ChangeOwner: /* change visible to SELECT */
3435  cmd_lockmode = AccessExclusiveLock;
3436  break;
3437 
3438  /*
3439  * Changing foreign table options may affect optimization.
3440  */
3441  case AT_GenericOptions:
3443  cmd_lockmode = AccessExclusiveLock;
3444  break;
3445 
3446  /*
3447  * These subcommands affect write operations only.
3448  */
3449  case AT_EnableTrig:
3450  case AT_EnableAlwaysTrig:
3451  case AT_EnableReplicaTrig:
3452  case AT_EnableTrigAll:
3453  case AT_EnableTrigUser:
3454  case AT_DisableTrig:
3455  case AT_DisableTrigAll:
3456  case AT_DisableTrigUser:
3457  cmd_lockmode = ShareRowExclusiveLock;
3458  break;
3459 
3460  /*
3461  * These subcommands affect write operations only. XXX
3462  * Theoretically, these could be ShareRowExclusiveLock.
3463  */
3464  case AT_ColumnDefault:
3465  case AT_AlterConstraint:
3466  case AT_AddIndex: /* from ADD CONSTRAINT */
3467  case AT_AddIndexConstraint:
3468  case AT_ReplicaIdentity:
3469  case AT_SetNotNull:
3470  case AT_EnableRowSecurity:
3471  case AT_DisableRowSecurity:
3472  case AT_ForceRowSecurity:
3473  case AT_NoForceRowSecurity:
3474  case AT_AddIdentity:
3475  case AT_DropIdentity:
3476  case AT_SetIdentity:
3477  cmd_lockmode = AccessExclusiveLock;
3478  break;
3479 
3480  case AT_AddConstraint:
3481  case AT_ProcessedConstraint: /* becomes AT_AddConstraint */
3482  case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
3483  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
3484  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
3485  if (IsA(cmd->def, Constraint))
3486  {
3487  Constraint *con = (Constraint *) cmd->def;
3488 
3489  switch (con->contype)
3490  {
3491  case CONSTR_EXCLUSION:
3492  case CONSTR_PRIMARY:
3493  case CONSTR_UNIQUE:
3494 
3495  /*
3496  * Cases essentially the same as CREATE INDEX. We
3497  * could reduce the lock strength to ShareLock if
3498  * we can work out how to allow concurrent catalog
3499  * updates. XXX Might be set down to
3500  * ShareRowExclusiveLock but requires further
3501  * analysis.
3502  */
3503  cmd_lockmode = AccessExclusiveLock;
3504  break;
3505  case CONSTR_FOREIGN:
3506 
3507  /*
3508  * We add triggers to both tables when we add a
3509  * Foreign Key, so the lock level must be at least
3510  * as strong as CREATE TRIGGER.
3511  */
3512  cmd_lockmode = ShareRowExclusiveLock;
3513  break;
3514 
3515  default:
3516  cmd_lockmode = AccessExclusiveLock;
3517  }
3518  }
3519  break;
3520 
3521  /*
3522  * These subcommands affect inheritance behaviour. Queries
3523  * started before us will continue to see the old inheritance
3524  * behaviour, while queries started after we commit will see
3525  * new behaviour. No need to prevent reads or writes to the
3526  * subtable while we hook it up though. Changing the TupDesc
3527  * may be a problem, so keep highest lock.
3528  */
3529  case AT_AddInherit:
3530  case AT_DropInherit:
3531  cmd_lockmode = AccessExclusiveLock;
3532  break;
3533 
3534  /*
3535  * These subcommands affect implicit row type conversion. They
3536  * have affects similar to CREATE/DROP CAST on queries. don't
3537  * provide for invalidating parse trees as a result of such
3538  * changes, so we keep these at AccessExclusiveLock.
3539  */
3540  case AT_AddOf:
3541  case AT_DropOf:
3542  cmd_lockmode = AccessExclusiveLock;
3543  break;
3544 
3545  /*
3546  * Only used by CREATE OR REPLACE VIEW which must conflict
3547  * with an SELECTs currently using the view.
3548  */
3549  case AT_ReplaceRelOptions:
3550  cmd_lockmode = AccessExclusiveLock;
3551  break;
3552 
3553  /*
3554  * These subcommands affect general strategies for performance
3555  * and maintenance, though don't change the semantic results
3556  * from normal data reads and writes. Delaying an ALTER TABLE
3557  * behind currently active writes only delays the point where
3558  * the new strategy begins to take effect, so there is no
3559  * benefit in waiting. In this case the minimum restriction
3560  * applies: we don't currently allow concurrent catalog
3561  * updates.
3562  */
3563  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
3564  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
3565  case AT_DropCluster: /* Uses MVCC in getIndexes() */
3566  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
3567  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
3568  cmd_lockmode = ShareUpdateExclusiveLock;
3569  break;
3570 
3571  case AT_SetLogged:
3572  case AT_SetUnLogged:
3573  cmd_lockmode = AccessExclusiveLock;
3574  break;
3575 
3576  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
3577  cmd_lockmode = ShareUpdateExclusiveLock;
3578  break;
3579 
3580  /*
3581  * Rel options are more complex than first appears. Options
3582  * are set here for tables, views and indexes; for historical
3583  * reasons these can all be used with ALTER TABLE, so we can't
3584  * decide between them using the basic grammar.
3585  */
3586  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
3587  * getTables() */
3588  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
3589  * getTables() */
3590  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
3591  break;
3592 
3593  case AT_AttachPartition:
3594  case AT_DetachPartition:
3595  cmd_lockmode = AccessExclusiveLock;
3596  break;
3597 
3598  default: /* oops */
3599  elog(ERROR, "unrecognized alter table type: %d",
3600  (int) cmd->subtype);
3601  break;
3602  }
3603 
3604  /*
3605  * Take the greatest lockmode from any subcommand
3606  */
3607  if (cmd_lockmode > lockmode)
3608  lockmode = cmd_lockmode;
3609  }
3610 
3611  return lockmode;
3612 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:567
int LOCKMODE
Definition: lockdefs.h:26
AlterTableType subtype
Definition: parsenodes.h:1806
#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:1593
#define AccessExclusiveLock
Definition: lockdefs.h:45
ConstrType contype
Definition: parsenodes.h:2092
#define elog
Definition: elog.h:219
Definition: pg_list.h:45

◆ AlterTableInternal()

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

Definition at line 3327 of file tablecmds.c.

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

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

3328 {
3329  Relation rel;
3330  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
3331 
3332  rel = relation_open(relid, lockmode);
3333 
3335 
3336  ATController(NULL, rel, cmds, recurse, lockmode);
3337 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3621
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:3372
void EventTriggerAlterTableRelid(Oid objectId)
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1124

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3252 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3253 {
3254  return RangeVarGetRelidExtended(stmt->relation, lockmode,
3255  stmt->missing_ok ? RVR_MISSING_OK : 0,
3257  (void *) stmt);
3258 }
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:13452
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:227
RangeVar * relation
Definition: parsenodes.h:1718

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 11079 of file tablecmds.c.

References AccessExclusiveLock, AccessShareLock, ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTableInternal(), AT_SetTableSpace, BTEqualStrategyNumber, ConditionalLockRelationOid(), ereport, errcode(), errmsg(), ERROR, EventTriggerAlterTableEnd(), EventTriggerAlterTableStart(), ForwardScanDirection, get_namespace_name(), get_rel_relkind(), get_relkind_objtype(), get_tablespace_name(), get_tablespace_oid(), GETSTRUCT, GetUserId(), heap_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(), AlterTableMoveAllStmt::roles, roleSpecsToIds(), ScanKeyInit(), and AlterTableCmd::subtype.

Referenced by ProcessUtilitySlow().

11080 {
11081  List *relations = NIL;
11082  ListCell *l;
11083  ScanKeyData key[1];
11084  Relation rel;
11085  HeapScanDesc scan;
11086  HeapTuple tuple;
11087  Oid orig_tablespaceoid;
11088  Oid new_tablespaceoid;
11089  List *role_oids = roleSpecsToIds(stmt->roles);
11090 
11091  /* Ensure we were not asked to move something we can't */
11092  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
11093  stmt->objtype != OBJECT_MATVIEW)
11094  ereport(ERROR,
11095  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
11096  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
11097 
11098  /* Get the orig and new tablespace OIDs */
11099  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
11100  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
11101 
11102  /* Can't move shared relations in to or out of pg_global */
11103  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
11104  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
11105  new_tablespaceoid == GLOBALTABLESPACE_OID)
11106  ereport(ERROR,
11107  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
11108  errmsg("cannot move relations in to or out of pg_global tablespace")));
11109 
11110  /*
11111  * Must have CREATE rights on the new tablespace, unless it is the
11112  * database default tablespace (which all users implicitly have CREATE
11113  * rights on).
11114  */
11115  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
11116  {
11117  AclResult aclresult;
11118 
11119  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
11120  ACL_CREATE);
11121  if (aclresult != ACLCHECK_OK)
11122  aclcheck_error(aclresult, OBJECT_TABLESPACE,
11123  get_tablespace_name(new_tablespaceoid));
11124  }
11125 
11126  /*
11127  * Now that the checks are done, check if we should set either to
11128  * InvalidOid because it is our database's default tablespace.
11129  */
11130  if (orig_tablespaceoid == MyDatabaseTableSpace)
11131  orig_tablespaceoid = InvalidOid;
11132 
11133  if (new_tablespaceoid == MyDatabaseTableSpace)
11134  new_tablespaceoid = InvalidOid;
11135 
11136  /* no-op */
11137  if (orig_tablespaceoid == new_tablespaceoid)
11138  return new_tablespaceoid;
11139 
11140  /*
11141  * Walk the list of objects in the tablespace and move them. This will
11142  * only find objects in our database, of course.
11143  */
11144  ScanKeyInit(&key[0],
11145  Anum_pg_class_reltablespace,
11146  BTEqualStrategyNumber, F_OIDEQ,
11147  ObjectIdGetDatum(orig_tablespaceoid));
11148 
11149  rel = heap_open(RelationRelationId, AccessShareLock);
11150  scan = heap_beginscan_catalog(rel, 1, key);
11151  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
11152  {
11153  Oid relOid = HeapTupleGetOid(tuple);
11154  Form_pg_class relForm;
11155 
11156  relForm = (Form_pg_class) GETSTRUCT(tuple);
11157 
11158  /*
11159  * Do not move objects in pg_catalog as part of this, if an admin
11160  * really wishes to do so, they can issue the individual ALTER
11161  * commands directly.
11162  *
11163  * Also, explicitly avoid any shared tables, temp tables, or TOAST
11164  * (TOAST will be moved with the main table).
11165  */
11166  if (IsSystemNamespace(relForm->relnamespace) || relForm->relisshared ||
11167  isAnyTempNamespace(relForm->relnamespace) ||
11168  relForm->relnamespace == PG_TOAST_NAMESPACE)
11169  continue;
11170 
11171  /* Only move the object type requested */
11172  if ((stmt->objtype == OBJECT_TABLE &&
11173  relForm->relkind != RELKIND_RELATION &&
11174  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
11175  (stmt->objtype == OBJECT_INDEX &&
11176  relForm->relkind != RELKIND_INDEX &&
11177  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
11178  (stmt->objtype == OBJECT_MATVIEW &&
11179  relForm->relkind != RELKIND_MATVIEW))
11180  continue;
11181 
11182  /* Check if we are only moving objects owned by certain roles */
11183  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
11184  continue;
11185 
11186  /*
11187  * Handle permissions-checking here since we are locking the tables
11188  * and also to avoid doing a bunch of work only to fail part-way. Note
11189  * that permissions will also be checked by AlterTableInternal().
11190  *
11191  * Caller must be considered an owner on the table to move it.
11192  */
11193  if (!pg_class_ownercheck(relOid, GetUserId()))
11195  NameStr(relForm->relname));
11196 
11197  if (stmt->nowait &&
11199  ereport(ERROR,
11200  (errcode(ERRCODE_OBJECT_IN_USE),
11201  errmsg("aborting because lock on relation \"%s.%s\" is not available",
11202  get_namespace_name(relForm->relnamespace),
11203  NameStr(relForm->relname))));
11204  else
11206 
11207  /* Add to our list of objects to move */
11208  relations = lappend_oid(relations, relOid);
11209  }
11210 
11211  heap_endscan(scan);
11213 
11214  if (relations == NIL)
11215  ereport(NOTICE,
11216  (errcode(ERRCODE_NO_DATA_FOUND),
11217  errmsg("no matching relations in tablespace \"%s\" found",
11218  orig_tablespaceoid == InvalidOid ? "(database default)" :
11219  get_tablespace_name(orig_tablespaceoid))));
11220 
11221  /* Everything is locked, loop through and move all of the relations. */
11222  foreach(l, relations)
11223  {
11224  List *cmds = NIL;
11226 
11227  cmd->subtype = AT_SetTableSpace;
11228  cmd->name = stmt->new_tablespacename;
11229 
11230  cmds = lappend(cmds, cmd);
11231 
11233  /* OID is set by AlterTableInternal */
11234  AlterTableInternal(lfirst_oid(l), cmds, false);
11236  }
11237 
11238  return new_tablespaceoid;
11239 }
#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:1382
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4701
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1572
Oid GetUserId(void)
Definition: miscinit.c:379
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:516
int errcode(int sqlerrcode)
Definition: elog.c:575
AlterTableType subtype
Definition: parsenodes.h:1806
#define heap_close(r, l)
Definition: heapam.h:97
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:605
Oid MyDatabaseTableSpace
Definition: globals.c:86
void EventTriggerAlterTableStart(Node *parsetree)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3349
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
HeapScanDesc heap_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
Definition: heapam.c:1412
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
AclResult
Definition: acl.h:178
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1835
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
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:564
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:4751
FormData_pg_class * Form_pg_class
Definition: pg_class.h:93
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:3327
#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:1428
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:576
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3175
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:707
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
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 12866 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, OnCommitItem::relid, RVR_MISSING_OK, and sequenceIsOwned().

Referenced by ExecAlterObjectSchemaStmt().

12867 {
12868  Relation rel;
12869  Oid relid;
12870  Oid oldNspOid;
12871  Oid nspOid;
12872  RangeVar *newrv;
12873  ObjectAddresses *objsMoved;
12874  ObjectAddress myself;
12875 
12877  stmt->missing_ok ? RVR_MISSING_OK : 0,
12879  (void *) stmt);
12880 
12881  if (!OidIsValid(relid))
12882  {
12883  ereport(NOTICE,
12884  (errmsg("relation \"%s\" does not exist, skipping",
12885  stmt->relation->relname)));
12886  return InvalidObjectAddress;
12887  }
12888 
12889  rel = relation_open(relid, NoLock);
12890 
12891  oldNspOid = RelationGetNamespace(rel);
12892 
12893  /* If it's an owned sequence, disallow moving it by itself. */
12894  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
12895  {
12896  Oid tableId;
12897  int32 colId;
12898 
12899  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
12900  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
12901  ereport(ERROR,
12902  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12903  errmsg("cannot move an owned sequence into another schema"),
12904  errdetail("Sequence \"%s\" is linked to table \"%s\".",
12906  get_rel_name(tableId))));
12907  }
12908 
12909  /* Get and lock schema OID and check its permissions. */
12910  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
12911  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
12912 
12913  /* common checks on switching namespaces */
12914  CheckSetNamespace(oldNspOid, nspOid);
12915 
12916  objsMoved = new_object_addresses();
12917  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
12918  free_object_addresses(objsMoved);
12919 
12920  ObjectAddressSet(myself, RelationRelationId, relid);
12921 
12922  if (oldschema)
12923  *oldschema = oldNspOid;
12924 
12925  /* close rel, but keep lock until commit */
12926  relation_close(rel, NoLock);
12927 
12928  return myself;
12929 }
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:500
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1270
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2130
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2401
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
signed int int32
Definition: c.h:313
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:12937
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:13452
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define RelationGetRelationName(relation)
Definition: rel.h:441
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:227
#define ereport(elevel, rest)
Definition: elog.h:122
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2947
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:527
#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:1124
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:448

◆ AlterTableNamespaceInternal()

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

Definition at line 12937 of file tablecmds.c.

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

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

12939 {
12940  Relation classRel;
12941 
12942  Assert(objsMoved != NULL);
12943 
12944  /* OK, modify the pg_class row and pg_depend entry */
12945  classRel = heap_open(RelationRelationId, RowExclusiveLock);
12946 
12947  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
12948  nspOid, true, objsMoved);
12949 
12950  /* Fix the table's row type too */
12951  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
12952  nspOid, false, false, objsMoved);
12953 
12954  /* Fix other dependent stuff */
12955  if (rel->rd_rel->relkind == RELKIND_RELATION ||
12956  rel->rd_rel->relkind == RELKIND_MATVIEW ||
12957  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12958  {
12959  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
12960  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
12961  objsMoved, AccessExclusiveLock);
12962  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
12963  false, objsMoved);
12964  }
12965 
12966  heap_close(classRel, RowExclusiveLock);
12967 }
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3578
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:84
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:13045
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:13090
#define RowExclusiveLock
Definition: lockdefs.h:38
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define Assert(condition)
Definition: c.h:699
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12975
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define RelationGetRelid(relation)
Definition: rel.h:407

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 13342 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().

13344 {
13345  ListCell *cur_item;
13346  ListCell *prev_item;
13347 
13348  prev_item = NULL;
13349  cur_item = list_head(on_commits);
13350 
13351  while (cur_item != NULL)
13352  {
13353  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
13354 
13355  if (!isCommit && oc->creating_subid == mySubid)
13356  {
13357  /* cur_item must be removed */
13358  on_commits = list_delete_cell(on_commits, cur_item, prev_item);
13359  pfree(oc);
13360  if (prev_item)
13361  cur_item = lnext(prev_item);
13362  else
13363  cur_item = list_head(on_commits);
13364  }
13365  else
13366  {
13367  /* cur_item must be preserved */
13368  if (oc->creating_subid == mySubid)
13369  oc->creating_subid = parentSubid;
13370  if (oc->deleting_subid == mySubid)
13371  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
13372  prev_item = cur_item;
13373  cur_item = lnext(prev_item);
13374  }
13375  }
13376 }
SubTransactionId creating_subid
Definition: tablecmds.c:120
void pfree(void *pointer)
Definition: mcxt.c:1031
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:480

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 13300 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().

13301 {
13302  ListCell *cur_item;
13303  ListCell *prev_item;
13304 
13305  prev_item = NULL;
13306  cur_item = list_head(on_commits);
13307 
13308  while (cur_item != NULL)
13309  {
13310  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
13311 
13312  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
13314  {
13315  /* cur_item must be removed */
13316  on_commits = list_delete_cell(on_commits, cur_item, prev_item);
13317  pfree(oc);
13318  if (prev_item)
13319  cur_item = lnext(prev_item);
13320  else
13321  cur_item = list_head(on_commits);
13322  }
13323  else
13324  {
13325  /* cur_item must be preserved */
13328  prev_item = cur_item;
13329  cur_item = lnext(prev_item);
13330  }
13331  }
13332 }
SubTransactionId creating_subid
Definition: tablecmds.c:120
void pfree(void *pointer)
Definition: mcxt.c:1031
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:480

◆ ATExecChangeOwner()

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

Definition at line 10255 of file tablecmds.c.

References ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, aclnewowner(), AlterTypeOwnerInternal(), ATExecChangeOwner(), CatalogTupleUpdate(), change_owner_fix_column_acls(), change_owner_recurse_to_sequences(), changeDependencyOnOwner(), check_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, NoLock, OBJECT_SCHEMA, ObjectIdGetDatum, pg_class_ownercheck(), pg_namespace_aclcheck(), PointerGetDatum, relation_close(), relation_open(), RelationGetDescr, RelationGetIndexList(), RelationGetRelationName, ReleaseSysCache(), RELOID, RowExclusiveLock, SearchSysCache1(), sequenceIsOwned(), superuser(), SysCacheGetAttr(), HeapTupleData::t_self, and WARNING.

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

10256 {
10257  Relation target_rel;
10258  Relation class_rel;
10259  HeapTuple tuple;
10260  Form_pg_class tuple_class;
10261 
10262  /*
10263  * Get exclusive lock till end of transaction on the target table. Use
10264  * relation_open so that we can work on indexes and sequences.
10265  */
10266  target_rel = relation_open(relationOid, lockmode);
10267 
10268  /* Get its pg_class tuple, too */
10269  class_rel = heap_open(RelationRelationId, RowExclusiveLock);
10270 
10271  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
10272  if (!HeapTupleIsValid(tuple))
10273  elog(ERROR, "cache lookup failed for relation %u", relationOid);
10274  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
10275 
10276  /* Can we change the ownership of this tuple? */
10277  switch (tuple_class->relkind)
10278  {
10279  case RELKIND_RELATION:
10280  case RELKIND_VIEW:
10281  case RELKIND_MATVIEW:
10282  case RELKIND_FOREIGN_TABLE:
10283  case RELKIND_PARTITIONED_TABLE:
10284  /* ok to change owner */
10285  break;
10286  case RELKIND_INDEX:
10287  if (!recursing)
10288  {
10289  /*
10290  * Because ALTER INDEX OWNER used to be allowed, and in fact
10291  * is generated by old versions of pg_dump, we give a warning
10292  * and do nothing rather than erroring out. Also, to avoid
10293  * unnecessary chatter while restoring those old dumps, say
10294  * nothing at all if the command would be a no-op anyway.
10295  */
10296  if (tuple_class->relowner != newOwnerId)
10297  ereport(WARNING,
10298  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10299  errmsg("cannot change owner of index \"%s\"",
10300  NameStr(tuple_class->relname)),
10301  errhint("Change the ownership of the index's table, instead.")));
10302  /* quick hack to exit via the no-op path */
10303  newOwnerId = tuple_class->relowner;
10304  }
10305  break;
10306  case RELKIND_PARTITIONED_INDEX:
10307  if (recursing)
10308  break;
10309  ereport(ERROR,
10310  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10311  errmsg("cannot change owner of index \"%s\"",
10312  NameStr(tuple_class->relname)),
10313  errhint("Change the ownership of the index's table, instead.")));
10314  break;
10315  case RELKIND_SEQUENCE:
10316  if (!recursing &&
10317  tuple_class->relowner != newOwnerId)
10318  {
10319  /* if it's an owned sequence, disallow changing it by itself */
10320  Oid tableId;
10321  int32 colId;
10322 
10323  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
10324  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
10325  ereport(ERROR,
10326  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10327  errmsg("cannot change owner of sequence \"%s\"",
10328  NameStr(tuple_class->relname)),
10329  errdetail("Sequence \"%s\" is linked to table \"%s\".",
10330  NameStr(tuple_class->relname),
10331  get_rel_name(tableId))));
10332  }
10333  break;
10334  case RELKIND_COMPOSITE_TYPE:
10335  if (recursing)
10336  break;
10337  ereport(ERROR,
10338  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10339  errmsg("\"%s\" is a composite type",
10340  NameStr(tuple_class->relname)),
10341  errhint("Use ALTER TYPE instead.")));
10342  break;
10343  case RELKIND_TOASTVALUE:
10344  if (recursing)
10345  break;
10346  /* FALL THRU */
10347  default:
10348  ereport(ERROR,
10349  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10350  errmsg("\"%s\" is not a table, view, sequence, or foreign table",
10351  NameStr(tuple_class->relname))));
10352  }
10353 
10354  /*
10355  * If the new owner is the same as the existing owner, consider the
10356  * command to have succeeded. This is for dump restoration purposes.
10357  */
10358  if (tuple_class->relowner != newOwnerId)
10359  {
10360  Datum repl_val[Natts_pg_class];
10361  bool repl_null[Natts_pg_class];
10362  bool repl_repl[Natts_pg_class];
10363  Acl *newAcl;
10364  Datum aclDatum;
10365  bool isNull;
10366  HeapTuple newtuple;
10367 
10368  /* skip permission checks when recursing to index or toast table */
10369  if (!recursing)
10370  {
10371  /* Superusers can always do it */
10372  if (!superuser())
10373  {
10374  Oid namespaceOid = tuple_class->relnamespace;
10375  AclResult aclresult;
10376 
10377  /* Otherwise, must be owner of the existing object */
10378  if (!pg_class_ownercheck(relationOid, GetUserId()))
10380  RelationGetRelationName(target_rel));
10381 
10382  /* Must be able to become new owner */
10383  check_is_member_of_role(GetUserId(), newOwnerId);
10384 
10385  /* New owner must have CREATE privilege on namespace */
10386  aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
10387  ACL_CREATE);
10388  if (aclresult != ACLCHECK_OK)
10389  aclcheck_error(aclresult, OBJECT_SCHEMA,
10390  get_namespace_name(namespaceOid));
10391  }
10392  }
10393 
10394  memset(repl_null, false, sizeof(repl_null));
10395  memset(repl_repl, false, sizeof(repl_repl));
10396 
10397  repl_repl[Anum_pg_class_relowner - 1] = true;
10398  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
10399 
10400  /*
10401  * Determine the modified ACL for the new owner. This is only
10402  * necessary when the ACL is non-null.
10403  */
10404  aclDatum = SysCacheGetAttr(RELOID, tuple,
10405  Anum_pg_class_relacl,
10406  &isNull);
10407  if (!isNull)
10408  {
10409  newAcl = aclnewowner(DatumGetAclP(aclDatum),
10410  tuple_class->relowner, newOwnerId);
10411  repl_repl[Anum_pg_class_relacl - 1] = true;
10412  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
10413  }
10414 
10415  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
10416 
10417  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
10418 
10419  heap_freetuple(newtuple);
10420 
10421  /*
10422  * We must similarly update any per-column ACLs to reflect the new
10423  * owner; for neatness reasons that's split out as a subroutine.
10424  */
10425  change_owner_fix_column_acls(relationOid,
10426  tuple_class->relowner,
10427  newOwnerId);
10428 
10429  /*
10430  * Update owner dependency reference, if any. A composite type has
10431  * none, because it's tracked for the pg_type entry instead of here;
10432  * indexes and TOAST tables don't have their own entries either.
10433  */
10434  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
10435  tuple_class->relkind != RELKIND_INDEX &&
10436  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
10437  tuple_class->relkind != RELKIND_TOASTVALUE)
10438  changeDependencyOnOwner(RelationRelationId, relationOid,
10439  newOwnerId);
10440 
10441  /*
10442  * Also change the ownership of the table's row type, if it has one
10443  */
10444  if (tuple_class->relkind != RELKIND_INDEX &&
10445  tuple_class->relkind != RELKIND_PARTITIONED_INDEX)
10446  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
10447 
10448  /*
10449  * If we are operating on a table or materialized view, also change
10450  * the ownership of any indexes and sequences that belong to the
10451  * relation, as well as its toast table (if it has one).
10452  */
10453  if (tuple_class->relkind == RELKIND_RELATION ||
10454  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
10455  tuple_class->relkind == RELKIND_MATVIEW ||
10456  tuple_class->relkind == RELKIND_TOASTVALUE)
10457  {
10458  List *index_oid_list;
10459  ListCell *i;
10460 
10461  /* Find all the indexes belonging to this relation */
10462  index_oid_list = RelationGetIndexList(target_rel);
10463 
10464  /* For each index, recursively change its ownership */
10465  foreach(i, index_oid_list)
10466  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
10467 
10468  list_free(index_oid_list);
10469  }
10470 
10471  if (tuple_class->relkind == RELKIND_RELATION ||
10472  tuple_class->relkind == RELKIND_MATVIEW)
10473  {
10474  /* If it has a toast table, recurse to change its ownership */
10475  if (tuple_class->reltoastrelid != InvalidOid)
10476  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
10477  true, lockmode);
10478 
10479  /* If it has dependent sequences, recurse to change them too */
10480  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
10481  }
10482  }
10483 
10484  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
10485 
10486  ReleaseSysCache(tuple);
10487  heap_close(class_rel, RowExclusiveLock);
10488  relation_close(target_rel, NoLock);
10489 }
int errhint(const char *fmt,...)
Definition: elog.c:987
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:500
#define RelationGetDescr(relation)
Definition: rel.h:433
Oid GetUserId(void)
Definition: miscinit.c:379
#define DatumGetAclP(X)
Definition: acl.h:121
#define PointerGetDatum(X)
Definition: postgres.h:541
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
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:1270
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3448
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4689
signed int int32
Definition: c.h:313
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:3349
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
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:441
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
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:10255
#define WARNING
Definition: elog.h:40
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
AclResult
Definition: acl.h:178
uintptr_t Datum
Definition: postgres.h:367
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:1294
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4751
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:10563
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4260
FormData_pg_class * Form_pg_class
Definition: pg_class.h:93
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:10498
int errmsg(const char *fmt,...)
Definition: elog.c:797
void list_free(List *list)
Definition: list.c:1133
int i
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:576
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1124
#define elog
Definition: elog.h:219
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1173
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

◆ check_of_type()

void check_of_type ( HeapTuple  typetuple)

Definition at line 5287 of file tablecmds.c.

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

Referenced by ATExecAddOf(), and transformOfType().

5288 {
5289  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
5290  bool typeOk = false;
5291 
5292  if (typ->typtype == TYPTYPE_COMPOSITE)
5293  {
5294  Relation typeRelation;
5295 
5296  Assert(OidIsValid(typ->typrelid));
5297  typeRelation = relation_open(typ->typrelid, AccessShareLock);
5298  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
5299 
5300  /*
5301  * Close the parent rel, but keep our AccessShareLock on it until xact
5302  * commit. That will prevent someone else from deleting or ALTERing
5303  * the type before the typed table creation/conversion commits.
5304  */
5305  relation_close(typeRelation, NoLock);
5306  }
5307  if (!typeOk)
5308  ereport(ERROR,
5309  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5310  errmsg("type %s is not a composite type",
5311  format_type_be(HeapTupleGetOid(typetuple)))));
5312 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1270
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
Form_pg_class rd_rel
Definition: rel.h:84
#define OidIsValid(objectId)
Definition: c.h:605
#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:699
FormData_pg_type * Form_pg_type
Definition: pg_type.h:248
int errmsg(const char *fmt,...)
Definition: elog.c:797
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1124
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:707

◆ CheckTableNotInUse()

void CheckTableNotInUse ( Relation  rel,
const char *  stmt 
)

Definition at line 3222 of file tablecmds.c.

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

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

3223 {
3224  int expected_refcnt;
3225 
3226  expected_refcnt = rel->rd_isnailed ? 2 : 1;
3227  if (rel->rd_refcnt != expected_refcnt)
3228  ereport(ERROR,
3229  (errcode(ERRCODE_OBJECT_IN_USE),
3230  /* translator: first %s is a SQL command, eg ALTER TABLE */
3231  errmsg("cannot %s \"%s\" because "
3232  "it is being used by active queries in this session",
3233  stmt, RelationGetRelationName(rel))));
3234 
3235  if (rel->rd_rel->relkind != RELKIND_INDEX &&
3236  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
3238  ereport(ERROR,
3239  (errcode(ERRCODE_OBJECT_IN_USE),
3240  /* translator: first %s is a SQL command, eg ALTER TABLE */
3241  errmsg("cannot %s \"%s\" because "
3242  "it has pending trigger events",
3243  stmt, RelationGetRelationName(rel))));
3244 }
bool rd_isnailed
Definition: rel.h:61
int errcode(int sqlerrcode)
Definition: elog.c:575
Form_pg_class rd_rel
Definition: rel.h:84
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define ereport(elevel, rest)
Definition: elog.h:122
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5629
int errmsg(const char *fmt,...)
Definition: elog.c:797
int rd_refcnt
Definition: rel.h:58
#define RelationGetRelid(relation)
Definition: rel.h:407

◆ createForeignKeyTriggers()

void createForeignKeyTriggers ( Relation  rel,
Oid  refRelOid,
Constraint fkconstraint,
Oid  constraintOid,
Oid  indexOid,
bool  create_action 
)

Definition at line 8796 of file tablecmds.c.

References CommandCounterIncrement(), createForeignKeyActionTriggers(), createForeignKeyCheckTriggers(), RelationData::rd_rel, and RelationGetRelid.

Referenced by ATAddForeignKeyConstraint(), and CloneForeignKeyConstraints().

8798 {
8799  /*
8800  * For the referenced side, create action triggers, if requested. (If the
8801  * referencing side is partitioned, there is still only one trigger, which
8802  * runs on the referenced side and points to the top of the referencing
8803  * hierarchy.)
8804  */
8805  if (create_action)
8806  createForeignKeyActionTriggers(rel, refRelOid, fkconstraint, constraintOid,
8807  indexOid);
8808 
8809  /*
8810  * For the referencing side, create the check triggers. We only need
8811  * these on the partitions.
8812  */
8813  if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
8815  fkconstraint, constraintOid, indexOid);
8816 
8818 }
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:8779
Form_pg_class rd_rel
Definition: rel.h:84
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:8658
void CommandCounterIncrement(void)
Definition: xact.c:914
#define RelationGetRelid(relation)
Definition: rel.h:407

◆ DefineRelation()

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

Definition at line 519 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, attnum, BuildDescForRelation(), check_default_partition_contents(), check_new_partition_bound(), CloneForeignKeyConstraints(), CloneRowTriggersToPartition(), 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(), 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, CookedConstraint::is_local, CookedConstraint::is_no_inherit, lappend(), lfirst, lfirst_oid, linitial_oid, list_concat(), list_free(), list_length(), make_parsestate(), MergeAttributes(), RawColumnDefault::missingMode, 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, RangeVar::relname, RangeVar::relpersistence, CookedConstraint::skip_validation, StoreCatalogInheritance(), StorePartitionBound(), StorePartitionKey(), StrNCpy, CreateStmt::tableElts, CreateStmt::tablespacename, tupleDesc::tdhasoid, transformPartitionBound(), transformPartitionSpec(), transformRelOptions(), RelationData::trigdesc, TupleDescAttr, typenameTypeId(), and view_reloptions().

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

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

◆ ExecuteTruncate()

void ExecuteTruncate ( TruncateStmt stmt)

Definition at line 1322 of file tablecmds.c.

References AccessExclusiveLock, TruncateStmt::behavior, ereport, errcode(), errhint(), errmsg(), ERROR, ExecuteTruncateGuts(), find_all_inheritors(), heap_close, heap_open(), heap_openrv(), RangeVar::inh, lappend(), lappend_oid(), lfirst, lfirst_oid, list_member_oid(), NIL, NoLock, RelationData::rd_rel, RelationGetRelid, RelationIsLogicallyLogged, TruncateStmt::relations, TruncateStmt::restart_seqs, and truncate_check_rel().

Referenced by standard_ProcessUtility().

1323 {
1324  List *rels = NIL;
1325  List *relids = NIL;
1326  List *relids_logged = NIL;
1327  ListCell *cell;
1328 
1329  /*
1330  * Open, exclusive-lock, and check all the explicitly-specified relations
1331  */
1332  foreach(cell, stmt->relations)
1333  {
1334  RangeVar *rv = lfirst(cell);
1335  Relation rel;
1336  bool recurse = rv->inh;
1337  Oid myrelid;
1338 
1339  rel = heap_openrv(rv, AccessExclusiveLock);
1340  myrelid = RelationGetRelid(rel);
1341  /* don't throw error for "TRUNCATE foo, foo" */
1342  if (list_member_oid(relids, myrelid))
1343  {
1345  continue;
1346  }
1347  truncate_check_rel(rel);
1348  rels = lappend(rels, rel);
1349  relids = lappend_oid(relids, myrelid);
1350  /* Log this relation only if needed for logical decoding */
1351  if (RelationIsLogicallyLogged(rel))
1352  relids_logged = lappend_oid(relids_logged, myrelid);
1353 
1354  if (recurse)
1355  {
1356  ListCell *child;
1357  List *children;
1358 
1359  children = find_all_inheritors(myrelid, AccessExclusiveLock, NULL);
1360 
1361  foreach(child, children)
1362  {
1363  Oid childrelid = lfirst_oid(child);
1364 
1365  if (list_member_oid(relids, childrelid))
1366  continue;
1367 
1368  /* find_all_inheritors already got lock */
1369  rel = heap_open(childrelid, NoLock);
1370  truncate_check_rel(rel);
1371  rels = lappend(rels, rel);
1372  relids = lappend_oid(relids, childrelid);
1373  /* Log this relation only if needed for logical decoding */
1374  if (RelationIsLogicallyLogged(rel))
1375  relids_logged = lappend_oid(relids_logged, childrelid);
1376  }
1377  }
1378  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1379  ereport(ERROR,
1380  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1381  errmsg("cannot truncate only a partitioned table"),
1382  errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1383  }
1384 
1385  ExecuteTruncateGuts(rels, relids, relids_logged,
1386  stmt->behavior, stmt->restart_seqs);
1387 
1388  /* And close the rels */
1389  foreach(cell, rels)
1390  {
1391  Relation rel = (Relation) lfirst(cell);
1392 
1393  heap_close(rel, NoLock);
1394  }
1395 }
#define NIL
Definition: pg_list.h:69
int errhint(const char *fmt,...)
Definition: elog.c:987
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:580
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
DropBehavior behavior
Definition: parsenodes.h:2608
struct RelationData * Relation
Definition: relcache.h:26
#define ERROR
Definition: elog.h:43
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs)
Definition: tablecmds.c:1411
List * relations
Definition: parsenodes.h:2606
#define NoLock
Definition: lockdefs.h:34
bool restart_seqs
Definition: parsenodes.h:2607
#define ereport(elevel, rest)
Definition: elog.h:122
bool inh
Definition: primnodes.h:69
List * lappend(List *list, void *datum)
Definition: list.c:128
static void truncate_check_rel(Relation rel)
Definition: tablecmds.c:1706
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1323
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define lfirst(lc)
Definition: pg_list.h:106
#define AccessExclusiveLock
Definition: lockdefs.h:45
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:166
int errmsg(const char *fmt,...)
Definition: elog.c:797
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:407
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ ExecuteTruncateGuts()

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

Definition at line 1411 of file tablecmds.c.

References AccessExclusiveLock, aclcheck_error(), ACLCHECK_NOT_OWNER, AfterTriggerBeginQuery(), AfterTriggerEndQuery(), Assert, CheckTableForSerializableConflictIn(), CreateExecutorState(), xl_heap_truncate::dbId, DROP_CASCADE, DROP_RESTRICT, ereport, errmsg(), EState::es_num_result_relations, EState::es_result_relation_info, EState::es_result_relations, ExecASTruncateTriggers(), ExecBSTruncateTriggers(), xl_heap_truncate::flags, FreeExecutorState(), GetCurrentSubTransactionId(), GetOldestMultiXactId(), getOwnedSequences(), GetUserId(), heap_close, heap_create_init_fork(), heap_open(), heap_truncate_check_FKs(), heap_truncate_find_FKs(), heap_truncate_one_rel(), i, InitResultRelInfo(), lappend(), lappend_oid(), lfirst, lfirst_oid, list_copy(), list_difference_ptr(), list_length(), MyDatabaseId, NIL, NoLock, NOTICE, xl_heap_truncate::nrelids, 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, RelationIsLogicallyLogged, RelationSetNewRelfilenode(), OnCommitItem::relid, ResetSequence(), SizeOfHeapTruncate, truncate_check_rel(), XLH_TRUNCATE_CASCADE, XLH_TRUNCATE_RESTART_SEQS, XLOG_HEAP_TRUNCATE, XLOG_INCLUDE_ORIGIN, XLogBeginInsert(), XLogInsert(), XLogLogicalInfoActive, XLogRegisterData(), and XLogSetRecordFlags().

Referenced by apply_handle_truncate(), and ExecuteTruncate().

1413 {
1414  List *rels;
1415  List *seq_relids = NIL;
1416  EState *estate;
1417  ResultRelInfo *resultRelInfos;
1418  ResultRelInfo *resultRelInfo;
1419  SubTransactionId mySubid;
1420  ListCell *cell;
1421  Oid *logrelids;
1422 
1423  /*
1424  * Open, exclusive-lock, and check all the explicitly-specified relations
1425  *
1426  * In CASCADE mode, suck in all referencing relations as well. This
1427  * requires multiple iterations to find indirectly-dependent relations. At
1428  * each phase, we need to exclusive-lock new rels before looking for their
1429  * dependencies, else we might miss something. Also, we check each rel as
1430  * soon as we open it, to avoid a faux pas such as holding lock for a long
1431  * time on a rel we have no permissions for.
1432  */
1433  rels = list_copy(explicit_rels);
1434  if (behavior == DROP_CASCADE)
1435  {
1436  for (;;)
1437  {
1438  List *newrelids;
1439 
1440  newrelids = heap_truncate_find_FKs(relids);
1441  if (newrelids == NIL)
1442  break; /* nothing else to add */
1443 
1444  foreach(cell, newrelids)
1445  {
1446  Oid relid = lfirst_oid(cell);
1447  Relation rel;
1448 
1449  rel = heap_open(relid, AccessExclusiveLock);
1450  ereport(NOTICE,
1451  (errmsg("truncate cascades to table \"%s\"",
1452  RelationGetRelationName(rel))));
1453  truncate_check_rel(rel);
1454  rels = lappend(rels, rel);
1455  relids = lappend_oid(relids, relid);
1456  /* Log this relation only if needed for logical decoding */
1457  if (RelationIsLogicallyLogged(rel))
1458  relids_logged = lappend_oid(relids_logged, relid);
1459  }
1460  }
1461  }
1462 
1463  /*
1464  * Check foreign key references. In CASCADE mode, this should be
1465  * unnecessary since we just pulled in all the references; but as a
1466  * cross-check, do it anyway if in an Assert-enabled build.
1467  */
1468 #ifdef USE_ASSERT_CHECKING
1469  heap_truncate_check_FKs(rels, false);
1470 #else
1471  if (behavior == DROP_RESTRICT)
1472  heap_truncate_check_FKs(rels, false);
1473 #endif
1474 
1475  /*
1476  * If we are asked to restart sequences, find all the sequences, lock them
1477  * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1478  * We want to do this early since it's pointless to do all the truncation
1479  * work only to fail on sequence permissions.
1480  */
1481  if (restart_seqs)
1482  {
1483  foreach(cell, rels)
1484  {
1485  Relation rel = (Relation) lfirst(cell);
1486  List *seqlist = getOwnedSequences(RelationGetRelid(rel), 0);
1487  ListCell *seqcell;
1488 
1489  foreach(seqcell, seqlist)
1490  {
1491  Oid seq_relid = lfirst_oid(seqcell);
1492  Relation seq_rel;
1493 
1494  seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1495 
1496  /* This check must match AlterSequence! */
1497  if (!pg_class_ownercheck(seq_relid, GetUserId()))
1499  RelationGetRelationName(seq_rel));
1500 
1501  seq_relids = lappend_oid(seq_relids, seq_relid);
1502 
1503  relation_close(seq_rel, NoLock);
1504  }
1505  }
1506  }
1507 
1508  /* Prepare to catch AFTER triggers. */
1510 
1511  /*
1512  * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1513  * each relation. We don't need to call ExecOpenIndices, though.
1514  */
1515  estate = CreateExecutorState();
1516  resultRelInfos = (ResultRelInfo *)
1517  palloc(list_length(rels) * sizeof(ResultRelInfo));
1518  resultRelInfo = resultRelInfos;
1519  foreach(cell, rels)
1520  {
1521  Relation rel = (Relation) lfirst(cell);
1522 
1523  InitResultRelInfo(resultRelInfo,
1524  rel,
1525  0, /* dummy rangetable index */
1526  NULL,
1527  0);
1528  resultRelInfo++;
1529  }
1530  estate->es_result_relations = resultRelInfos;
1531  estate->es_num_result_relations = list_length(rels);
1532 
1533  /*
1534  * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
1535  * truncating (this is because one of them might throw an error). Also, if
1536  * we were to allow them to prevent statement execution, that would need
1537  * to be handled here.
1538  */
1539  resultRelInfo = resultRelInfos;
1540  foreach(cell, rels)
1541  {
1542  estate->es_result_relation_info = resultRelInfo;
1543  ExecBSTruncateTriggers(estate, resultRelInfo);
1544  resultRelInfo++;
1545  }
1546 
1547  /*
1548  * OK, truncate each table.
1549  */
1550  mySubid = GetCurrentSubTransactionId();
1551 
1552  foreach(cell, rels)
1553  {
1554  Relation rel = (Relation) lfirst(cell);
1555 
1556  /* Skip partitioned tables as there is nothing to do */
1557  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1558  continue;
1559 
1560  /*
1561  * Normally, we need a transaction-safe truncation here. However, if
1562  * the table was either created in the current (sub)transaction or has
1563  * a new relfilenode in the current (sub)transaction, then we can just
1564  * truncate it in-place, because a rollback would cause the whole
1565  * table or the current physical file to be thrown away anyway.
1566  */
1567  if (rel->rd_createSubid == mySubid ||
1568  rel->rd_newRelfilenodeSubid == mySubid)
1569  {
1570  /* Immediate, non-rollbackable truncation is OK */
1571  heap_truncate_one_rel(rel);
1572  }
1573  else
1574  {
1575  Oid heap_relid;
1576  Oid toast_relid;
1577  MultiXactId minmulti;
1578 
1579  /*
1580  * This effectively deletes all rows in the table, and may be done
1581  * in a serializable transaction. In that case we must record a
1582  * rw-conflict in to this transaction from each transaction
1583  * holding a predicate lock on the table.
1584  */
1586 
1587  minmulti = GetOldestMultiXactId();
1588 
1589  /*
1590  * Need the full transaction-safe pushups.
1591  *
1592  * Create a new empty storage file for the relation, and assign it
1593  * as the relfilenode value. The old storage file is scheduled for
1594  * deletion at commit.
1595  */
1596  RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence,
1597  RecentXmin, minmulti);
1598  if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
1599  heap_create_init_fork(rel);
1600 
1601  heap_relid = RelationGetRelid(rel);
1602  toast_relid = rel->rd_rel->reltoastrelid;
1603 
1604  /*
1605  * The same for the toast table, if any.
1606  */
1607  if (OidIsValid(toast_relid))
1608  {
1609  rel = relation_open(toast_relid, AccessExclusiveLock);
1610  RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence,
1611  RecentXmin, minmulti);
1612  if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
1613  heap_create_init_fork(rel);
1614  heap_close(rel, NoLock);
1615  }
1616 
1617  /*
1618  * Reconstruct the indexes to match, and we're done.
1619  */
1621  }
1622 
1623  pgstat_count_truncate(rel);
1624  }
1625 
1626  /*
1627  * Restart owned sequences if we were asked to.
1628  */
1629  foreach(cell, seq_relids)
1630  {
1631  Oid seq_relid = lfirst_oid(cell);
1632 
1633  ResetSequence(seq_relid);
1634  }
1635 
1636  /*
1637  * Write a WAL record to allow this set of actions to be logically
1638  * decoded.
1639  *
1640  * Assemble an array of relids so we can write a single WAL record for the
1641  * whole action.
1642  */
1643  if (list_length(relids_logged) > 0)
1644  {
1645  xl_heap_truncate xlrec;
1646  int i = 0;
1647 
1648  /* should only get here if wal_level >= logical */
1650 
1651  logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
1652  foreach(cell, relids_logged)
1653  logrelids[i++] = lfirst_oid(cell);
1654 
1655  xlrec.dbId = MyDatabaseId;
1656  xlrec.nrelids = list_length(relids_logged);
1657  xlrec.flags = 0;
1658  if (behavior == DROP_CASCADE)
1659  xlrec.flags |= XLH_TRUNCATE_CASCADE;
1660  if (restart_seqs)
1662 
1663  XLogBeginInsert();
1664  XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
1665  XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
1666 
1668 
1669  (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
1670  }
1671 
1672  /*
1673  * Process all AFTER STATEMENT TRUNCATE triggers.
1674  */
1675  resultRelInfo = resultRelInfos;
1676  foreach(cell, rels)
1677  {
1678  estate->es_result_relation_info = resultRelInfo;
1679  ExecASTruncateTriggers(estate, resultRelInfo);
1680  resultRelInfo++;
1681  }
1682 
1683  /* Handle queued AFTER triggers */
1684  AfterTriggerEndQuery(estate);
1685 
1686  /* We can clean up the EState now */
1687  FreeExecutorState(estate);
1688 
1689  /*
1690  * Close any rels opened by CASCADE (can't do this while EState still
1691  * holds refs)
1692  */
1693  rels = list_difference_ptr(rels, explicit_rels);
1694  foreach(cell, rels)
1695  {
1696  Relation rel = (Relation) lfirst(cell);
1697 
1698  heap_close(rel, NoLock);
1699  }
1700 }
#define NIL
Definition: pg_list.h:69
#define XLH_TRUNCATE_CASCADE
Definition: heapam_xlog.h:116
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, Relation partition_root, int instrument_options)
Definition: execMain.c:1305
void RelationSetNewRelfilenode(Relation relation, char persistence, TransactionId freezeXid, MultiXactId minmulti)
Definition: relcache.c:3334
Oid GetUserId(void)
Definition: miscinit.c:379
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3057
List * list_difference_ptr(const List *list1, const List *list2)
Definition: list.c:884
List * list_copy(const List *oldlist)
Definition: list.c:1160
TransactionId RecentXmin
Definition: snapmgr.c:165
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3094
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1270
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:81
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:192
uint32 SubTransactionId
Definition: c.h:478
#define heap_close(r, l)
Definition: heapam.h:97
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:580
Form_pg_class rd_rel
Definition: rel.h:84
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:605
void FreeExecutorState(EState *estate)
Definition: execUtils.c:188
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3349
struct RelationData * Relation
Definition: relcache.h:26
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3176
#define XLogLogicalInfoActive()
Definition: xlog.h:163
struct ResultRelInfo ResultRelInfo
#define NoLock
Definition: lockdefs.h:34
void heap_create_init_fork(Relation rel)
Definition: heap.c:1391
ResultRelInfo * es_result_relations
Definition: execnodes.h:490
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3228
#define RelationGetRelationName(relation)
Definition: rel.h:441
void pgstat_count_truncate(Relation rel)
Definition: pgstat.c:2008
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:397
#define ereport(elevel, rest)
Definition: elog.h:122
EState * CreateExecutorState(void)
Definition: execUtils.c:80
List * lappend(List *list, void *datum)
Definition: list.c:128
SubTransactionId rd_createSubid
Definition: rel.h:80
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
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:1706
Oid MyDatabaseId
Definition: globals.c:84
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
int es_num_result_relations
Definition: execnodes.h:491
#define XLH_TRUNCATE_RESTART_SEQS
Definition: heapam_xlog.h:117
#define XLOG_HEAP_TRUNCATE
Definition: heapam_xlog.h:35
#define NOTICE
Definition: elog.h:37
void AfterTriggerBeginQuery(void)
Definition: trigger.c:4766
TransactionId MultiXactId
Definition: c.h:484
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:641
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4751
#define SizeOfHeapTruncate
Definition: heapam_xlog.h:132
static int list_length(const List *l)
Definition: pg_list.h:89
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4364
#define AccessExclusiveLock
Definition: lockdefs.h:45
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:4786
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1124
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:139
void ResetSequence(Oid seq_relid)
Definition: sequence.c:269
void XLogBeginInsert(void)
Definition: xloginsert.c:120
bool reindex_relation(Oid relid, int flags, int options)
Definition: index.c:3834
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:407
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3186
#define lfirst_oid(lc)
Definition: pg_list.h:108
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:492

◆ find_composite_type_dependencies()

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

Definition at line 5122 of file tablecmds.c.

References AccessShareLock, BTEqualStrategyNumber, check_stack_depth(), DependReferenceIndexId, 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, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), and TupleDescAttr.

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

5124 {
5125  Relation depRel;
5126  ScanKeyData key[2];
5127  SysScanDesc depScan;
5128  HeapTuple depTup;
5129 
5130  /* since this function recurses, it could be driven to stack overflow */
5132 
5133  /*
5134  * We scan pg_depend to find those things that depend on the given type.
5135  * (We assume we can ignore refobjsubid for a type.)
5136  */
5137  depRel = heap_open(DependRelationId, AccessShareLock);
5138 
5139  ScanKeyInit(&key[0],
5140  Anum_pg_depend_refclassid,
5141  BTEqualStrategyNumber, F_OIDEQ,
5142  ObjectIdGetDatum(TypeRelationId));
5143  ScanKeyInit(&key[1],
5144  Anum_pg_depend_refobjid,
5145  BTEqualStrategyNumber, F_OIDEQ,
5146  ObjectIdGetDatum(typeOid));
5147 
5148  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
5149  NULL, 2, key);
5150 
5151  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
5152  {
5153  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
5154  Relation rel;
5155  Form_pg_attribute att;
5156 
5157  /* Check for directly dependent types */
5158  if (pg_depend->classid == TypeRelationId)
5159  {
5160  /*
5161  * This must be an array, domain, or range containing the given
5162  * type, so recursively check for uses of this type. Note that
5163  * any error message will mention the original type not the
5164  * container; this is intentional.
5165  */
5166  find_composite_type_dependencies(pg_depend->objid,
5167  origRelation, origTypeName);
5168  continue;
5169  }
5170 
5171  /* Else, ignore dependees that aren't user columns of relations */
5172  /* (we assume system columns are never of interesting types) */
5173  if (pg_depend->classid != RelationRelationId ||
5174  pg_depend->objsubid <= 0)
5175  continue;
5176 
5177  rel = relation_open(pg_depend->objid, AccessShareLock);
5178  att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
5179 
5180  if (rel->rd_rel->relkind == RELKIND_RELATION ||
5181  rel->rd_rel->relkind == RELKIND_MATVIEW ||
5182  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5183  {
5184  if (origTypeName)
5185  ereport(ERROR,
5186  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5187  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5188  origTypeName,
5190  NameStr(att->attname))));
5191  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
5192  ereport(ERROR,
5193  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5194  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5195  RelationGetRelationName(origRelation),
5197  NameStr(att->attname))));
5198  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
5199  ereport(ERROR,
5200  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5201  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
5202  RelationGetRelationName(origRelation),
5204  NameStr(att->attname))));
5205  else
5206  ereport(ERROR,
5207  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5208  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
5209  RelationGetRelationName(origRelation),
5211  NameStr(att->attname))));
5212  }
5213  else if (OidIsValid(rel->rd_rel->reltype))
5214  {
5215  /*
5216  * A view or composite type itself isn't a problem, but we must
5217  * recursively check for indirect dependencies via its rowtype.
5218  */
5220  origRelation, origTypeName);
5221  }
5222 
5224  }
5225 
5226  systable_endscan(depScan);
5227 
5229 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
#define DependReferenceIndexId
Definition: indexing.h:148
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:5122
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1270
Form_pg_class rd_rel
Definition: rel.h:84
#define OidIsValid(objectId)
Definition: c.h:605
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:331
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:419
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
void check_stack_depth(void)
Definition: postgres.c:3159
#define RelationGetRelationName(relation)
Definition: rel.h:441
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:71
#define ereport(elevel, rest)
Definition: elog.h:122
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
TupleDesc rd_att
Definition: rel.h:85
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:576
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:1124
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ PartConstraintImpliedByRelConstraint()

bool PartConstraintImpliedByRelConstraint ( Relation  scanrel,
List partConstraint 
)

Definition at line 13879 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(), NullTest::location, 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_partition_contents(), and QueuePartitionConstraintValidation().

13881 {
13882  List *existConstraint = NIL;
13883  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
13884  int num_check,
13885  i;
13886 
13887  if (constr && constr->has_not_null)
13888  {
13889  int natts = scanrel->rd_att->natts;
13890 
13891  for (i = 1; i <= natts; i++)
13892  {
13893  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
13894 
13895  if (att->attnotnull && !att->attisdropped)
13896  {
13897  NullTest *ntest = makeNode(NullTest);
13898 
13899  ntest->arg = (Expr *) makeVar(1,
13900  i,
13901  att->atttypid,
13902  att->atttypmod,
13903  att->attcollation,
13904  0);
13905  ntest->nulltesttype = IS_NOT_NULL;
13906 
13907  /*
13908  * argisrow=false is correct even for a composite column,
13909  * because attnotnull does not represent a SQL-spec IS NOT
13910  * NULL test in such a case, just IS DISTINCT FROM NULL.
13911  */
13912  ntest->argisrow = false;
13913  ntest->location = -1;
13914  existConstraint = lappend(existConstraint, ntest);
13915  }
13916  }
13917  }
13918 
13919  num_check = (constr != NULL) ? constr->num_check : 0;
13920  for (i = 0; i < num_check; i++)
13921  {
13922  Node *cexpr;
13923 
13924  /*
13925  * If this constraint hasn't been fully validated yet, we must ignore
13926  * it here.
13927  */
13928  if (!constr->check[i].ccvalid)
13929  continue;
13930 
13931  cexpr = stringToNode(constr->check[i].ccbin);
13932 
13933  /*
13934  * Run each expression through const-simplification and
13935  * canonicalization. It is necessary, because we will be comparing it
13936  * to similarly-processed partition constraint expressions, and may
13937  * fail to detect valid matches without this.
13938  */
13939  cexpr = eval_const_expressions(NULL, cexpr);
13940  cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true);
13941 
13942  existConstraint = list_concat(existConstraint,
13943  make_ands_implicit((Expr *) cexpr));
13944  }
13945 
13946  /*
13947  * Try to make the proof. Since we are comparing CHECK constraints, we
13948  * need to use weak implication, i.e., we assume existConstraint is
13949  * not-false and try to prove the same for partConstraint.
13950  *
13951  * Note that predicate_implied_by assumes its first argument is known
13952  * immutable. That should always be true for partition constraints, so we
13953  * don't test it here.
13954  */
13955  return predicate_implied_by(partConstraint, existConstraint, true);
13956 }
#define NIL
Definition: pg_list.h:69
void * stringToNode(char *str)
Definition: read.c:39
#define RelationGetDescr(relation)
Definition: rel.h:433
ConstrCheck * check
Definition: tupdesc.h:42
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
char * ccbin
Definition: tupdesc.h:33
Definition: nodes.h:516
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2460
List * list_concat(List *list1, List *list2)
Definition: list.c:321
int natts
Definition: tupdesc.h:82
List * make_ands_implicit(Expr *clause)
Definition: clauses.c:379
Expr * arg
Definition: primnodes.h:1187
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:291
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
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:46
List * lappend(List *list, void *datum)
Definition: list.c:128
TupleDesc rd_att
Definition: rel.h:85
NullTestType nulltesttype
Definition: primnodes.h:1188
#define makeNode(_type_)
Definition: nodes.h:564
int location
Definition: primnodes.h:1190
bool ccvalid
Definition: tupdesc.h:34
int i
bool argisrow
Definition: primnodes.h:1189
uint16 num_check
Definition: tupdesc.h:45
bool predicate_implied_by(List *predicate_list, List *clause_list, bool weak)
Definition: predtest.c:149
Definition: pg_list.h:45

◆ PreCommit_on_commit_actions()

void PreCommit_on_commit_actions ( void  )

Definition at line 13229 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(), OnCommitItem::relid, and XACT_FLAGS_ACCESSEDTEMPREL.

Referenced by CommitTransaction(), and PrepareTransaction().

13230 {
13231  ListCell *l;
13232  List *oids_to_truncate = NIL;
13233 
13234  foreach(l, on_commits)
13235  {
13236  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
13237 
13238  /* Ignore entry if already dropped in this xact */
13240  continue;
13241 
13242  switch (oc->oncommit)
13243  {
13244  case ONCOMMIT_NOOP:
13246  /* Do nothing (there shouldn't be such entries, actually) */
13247  break;
13248  case ONCOMMIT_DELETE_ROWS:
13249 
13250  /*
13251  * If this transaction hasn't accessed any temporary
13252  * relations, we can skip truncating ON COMMIT DELETE ROWS
13253  * tables, as they must still be empty.
13254  */
13256  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
13257  break;
13258  case ONCOMMIT_DROP:
13259  {
13260  ObjectAddress object;
13261 
13262  object.classId = RelationRelationId;
13263  object.objectId = oc->relid;
13264  object.objectSubId = 0;
13265 
13266  /*
13267  * Since this is an automatic drop, rather than one
13268  * directly initiated by the user, we pass the
13269  * PERFORM_DELETION_INTERNAL flag.
13270  */
13271  performDeletion(&object,
13273 
13274  /*
13275  * Note that table deletion will call
13276  * remove_on_commit_action, so the entry should get marked
13277  * as deleted.
13278  */
13280  break;
13281  }
13282  }
13283  }
13284  if (oids_to_truncate != NIL)
13285  {
13286  heap_truncate(oids_to_truncate);
13287  CommandCounterIncrement(); /* XXX needed? */
13288  }
13289 }
#define NIL
Definition: pg_list.h:69
OnCommitAction oncommit
Definition: tablecmds.c:111
#define XACT_FLAGS_ACCESSEDTEMPREL
Definition: xact.h:93
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:300
int MyXactFlags
Definition: xact.c:117
SubTransactionId deleting_subid
Definition: tablecmds.c:121
void CommandCounterIncrement(void)
Definition: xact.c:914
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
void heap_truncate(List *relids)
Definition: heap.c:3016
#define InvalidSubTransactionId
Definition: c.h:480
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 13420 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().

13422 {
13423  HeapTuple tuple;
13424 
13425  /* Nothing to do if the relation was not found. */
13426  if (!OidIsValid(relId))
13427  return;
13428 
13429  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
13430  if (!HeapTupleIsValid(tuple)) /* should not happen */
13431  elog(ERROR, "cache lookup failed for relation %u", relId);
13432 
13433  if (!pg_class_ownercheck(relId, GetUserId()))
13435  relation->relname);
13436 
13437  if (!allowSystemTableMods &&
13438  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
13439  ereport(ERROR,
13440  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
13441  errmsg("permission denied: \"%s\" is a system catalog",
13442  relation->relname)));
13443 
13444  ReleaseSysCache(tuple);
13445 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
Oid GetUserId(void)
Definition: miscinit.c:379
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
int errcode(int sqlerrcode)
Definition: elog.c:575
#define OidIsValid(objectId)
Definition: c.h:605
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:3349
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#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:119
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4751
FormData_pg_class * Form_pg_class
Definition: pg_class.h:93
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 13387 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(), relkind, and RangeVar::relname.

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

13389 {
13390  char relkind;
13391 
13392  /* Nothing to do if the relation was not found. */
13393  if (!OidIsValid(relId))
13394  return;
13395 
13396  /*
13397  * If the relation does exist, check whether it's an index. But note that
13398  * the relation might have been dropped between the time we did the name
13399  * lookup and now. In that case, there's nothing to do.
13400  */
13401  relkind = get_rel_relkind(relId);
13402  if (!relkind)
13403  return;
13404  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
13405  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
13406  ereport(ERROR,
13407  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13408  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
13409 
13410  /* Check permissions */
13411  if (!pg_class_ownercheck(relId, GetUserId()))
13413 }
Oid GetUserId(void)
Definition: miscinit.c:379
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
int errcode(int sqlerrcode)
Definition: elog.c:575
#define OidIsValid(objectId)
Definition: c.h:605
char relkind
Definition: pg_class.h:51
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3349
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4751
int errmsg(const char *fmt,...)
Definition: elog.c:797
ObjectType get_relkind_objtype(char relkind)

◆ register_on_commit_action()

void register_on_commit_action ( Oid  relid,
OnCommitAction  action 
)

Definition at line 13175 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().

13176 {
13177  OnCommitItem *oc;
13178  MemoryContext oldcxt;
13179 
13180  /*
13181  * We needn't bother registering the relation unless there is an ON COMMIT
13182  * action we need to take.
13183  */
13185  return;
13186 
13188 
13189  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
13190  oc->relid = relid;
13191  oc->oncommit = action;
13194 
13195  on_commits = lcons(oc, on_commits);
13196 
13197  MemoryContextSwitchTo(oldcxt);
13198 }
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:641
#define InvalidSubTransactionId
Definition: c.h:480
void * palloc(Size size)
Definition: mcxt.c:924
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ remove_on_commit_action()

void remove_on_commit_action ( Oid  relid)

Definition at line 13206 of file tablecmds.c.

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

Referenced by heap_drop_with_catalog().

13207 {
13208  ListCell *l;
13209 
13210  foreach(l, on_commits)
13211  {
13212  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
13213 
13214  if (oc->relid == relid)
13215  {
13217  break;
13218  }
13219  }
13220 }
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:641

◆ RemoveRelations()

void RemoveRelations ( DropStmt drop)

Definition at line 1078 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(), relkind, DropRelationCallbackState::relkind, DropStmt::removeType, RVR_MISSING_OK, and ShareUpdateExclusiveLock.

Referenced by ExecDropStmt().

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

◆ renameatt()

ObjectAddress renameatt ( RenameStmt stmt)

Definition at line 2893 of file tablecmds.c.

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

Referenced by ExecRenameStmt().

2894 {
2895  Oid relid;
2897  ObjectAddress address;
2898 
2899  /* lock level taken here should match renameatt_internal */
2901  stmt->missing_ok ? RVR_MISSING_OK : 0,
2903  NULL);
2904 
2905  if (!OidIsValid(relid))
2906  {
2907  ereport(NOTICE,
2908  (errmsg("relation \"%s\" does not exist, skipping",
2909  stmt->relation->relname)));
2910  return InvalidObjectAddress;
2911  }
2912 
2913  attnum =
2914  renameatt_internal(relid,
2915  stmt->subname, /* old att name */
2916  stmt->newname, /* new att name */
2917  stmt->relation->inh, /* recursive? */
2918  false, /* recursing? */
2919  0, /* expected inhcount */
2920  stmt->behavior);
2921 
2922  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
2923 
2924  return address;
2925 }
char * subname
Definition: parsenodes.h:2847
char * newname
Definition: parsenodes.h:2849
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2851
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:227
#define ereport(elevel, rest)
Definition: elog.h:122
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:2845
int16 attnum
Definition: pg_attribute.h:79
#define NOTICE
Definition: elog.h:37
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:2873
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:2728
#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:2850
int16 AttrNumber
Definition: attnum.h:21

◆ renameatt_type()

ObjectAddress renameatt_type ( RenameStmt stmt)

◆ RenameConstraint()

ObjectAddress RenameConstraint ( RenameStmt stmt)

Definition at line 3030 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, RVR_MISSING_OK, SearchSysCache1(), RenameStmt::subname, typenameTypeId(), and TYPEOID.

Referenced by ExecRenameStmt().

3031 {
3032  Oid relid = InvalidOid;
3033  Oid typid = InvalidOid;
3034 
3035  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3036  {
3037  Relation rel;
3038  HeapTuple tup;
3039 
3041  rel = heap_open(TypeRelationId, RowExclusiveLock);
3042  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3043  if (!HeapTupleIsValid(tup))
3044  elog(ERROR, "cache lookup failed for type %u", typid);
3045  checkDomainOwner(tup);
3046  ReleaseSysCache(tup);
3047  heap_close(rel, NoLock);
3048  }
3049  else
3050  {
3051  /* lock level taken here should match rename_constraint_internal */
3053  stmt->missing_ok ? RVR_MISSING_OK : 0,
3055  NULL);
3056  if (!OidIsValid(relid))
3057  {
3058  ereport(NOTICE,
3059  (errmsg("relation \"%s\" does not exist, skipping",
3060  stmt->relation->relname)));
3061  return InvalidObjectAddress;
3062  }
3063  }
3064 
3065  return
3066  rename_constraint_internal(relid, typid,
3067  stmt->subname,
3068  stmt->newname,
3069  (stmt->relation &&
3070  stmt->relation->inh), /* recursive? */
3071  false, /* recursing? */
3072  0 /* expected inhcount */ );
3073 
3074 }
char * subname
Definition: parsenodes.h:2847
ObjectType renameType
Definition: parsenodes.h:2843
#define castNode(_type_, nodeptr)
Definition: nodes.h:585
#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:2931
char * newname
Definition: parsenodes.h:2849
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2851
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Node * object
Definition: parsenodes.h:2846
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:227
#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:1294
RangeVar * relation
Definition: parsenodes.h:2845
#define InvalidOid
Definition: postgres_ext.h:36
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:2873
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3037
#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 3081 of file tablecmds.c.

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

Referenced by ExecRenameStmt().

3082 {
3083  Oid relid;
3084  ObjectAddress address;
3085 
3086  /*
3087  * Grab an exclusive lock on the target table, index, sequence, view,
3088  * materialized view, or foreign table, which we will NOT release until
3089  * end of transaction.
3090  *
3091  * Lock level used here should match RenameRelationInternal, to avoid lock
3092  * escalation.
3093  */
3095  stmt->missing_ok ? RVR_MISSING_OK : 0,
3097  (void *) stmt);
3098 
3099  if (!OidIsValid(relid))
3100  {
3101  ereport(NOTICE,
3102  (errmsg("relation \"%s\" does not exist, skipping",
3103  stmt->relation->relname)));
3104  return InvalidObjectAddress;
3105  }
3106 
3107  /* Do the work */
3108  RenameRelationInternal(relid, stmt->newname, false);
3109 
3110  ObjectAddressSet(address, RelationRelationId, relid);
3111 
3112  return address;
3113 }
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
Definition: tablecmds.c:3125
char * newname
Definition: parsenodes.h:2849
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
char * relname
Definition: primnodes.h:68
bool missing_ok
Definition: parsenodes.h:2851
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:13452
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:227
#define ereport(elevel, rest)
Definition: elog.h:122
RangeVar * relation
Definition: parsenodes.h:2845
#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 3125 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, RELOID, RenameConstraintById(), RenameTypeInternal(), RowExclusiveLock, SearchSysCacheCopy1, and HeapTupleData::t_self.

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

3126 {
3127  Relation targetrelation;
3128  Relation relrelation; /* for RELATION relation */
3129  HeapTuple reltup;
3130  Form_pg_class relform;
3131  Oid namespaceId;
3132 
3133  /*
3134  * Grab an exclusive lock on the target table, index, sequence, view,
3135  * materialized view, or foreign table, which we will NOT release until
3136  * end of transaction.
3137  */
3138  targetrelation = relation_open(myrelid, AccessExclusiveLock);
3139  namespaceId = RelationGetNamespace(targetrelation);
3140 
3141  /*
3142  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3143  */
3144  relrelation = heap_open(RelationRelationId, RowExclusiveLock);
3145 
3146  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3147  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3148  elog(ERROR, "cache lookup failed for relation %u", myrelid);
3149  relform = (Form_pg_class) GETSTRUCT(reltup);
3150 
3151  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3152  ereport(ERROR,
3153  (errcode(ERRCODE_DUPLICATE_TABLE),
3154  errmsg("relation \"%s\" already exists",
3155  newrelname)));
3156 
3157  /*
3158  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
3159  * because it's a copy...)
3160  */
3161  namestrcpy(&(relform->relname), newrelname);
3162 
3163  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3164 
3165  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
3166  InvalidOid, is_internal);
3167 
3168  heap_freetuple(reltup);
3169  heap_close(relrelation, RowExclusiveLock);
3170 
3171  /*
3172  * Also rename the associated type, if any.
3173  */
3174  if (OidIsValid(targetrelation->rd_rel->reltype))
3175  RenameTypeInternal(targetrelation->rd_rel->reltype,
3176  newrelname, namespaceId);
3177 
3178  /*
3179  * Also rename the associated constraint, if any.
3180  */
3181  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3182  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3183  {
3184  Oid constraintId = get_index_constraint(myrelid);
3185 
3186  if (OidIsValid(constraintId))
3187  RenameConstraintById(constraintId, newrelname);
3188  }
3189 
3190  /*
3191  * Close rel, but keep exclusive lock!
3192  */
3193  relation_close(targetrelation, NoLock);
3194 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1270
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:84
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
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:605
#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:492
#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
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:691
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
FormData_pg_class * Form_pg_class
Definition: pg_class.h:93
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:797
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1124
#define elog
Definition: elog.h:219
#define RelationGetNamespace(relation)
Definition: rel.h:448

◆ SetRelationHasSubclass()

void SetRelationHasSubclass ( Oid  relationId,
bool  relhassubclass 
)

Definition at line 2646 of file tablecmds.c.

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

Referenced by acquire_inherited_sample_rows(), and StoreCatalogInheritance1().

2647 {
2648  Relation relationRelation;
2649  HeapTuple tuple;
2650  Form_pg_class classtuple;
2651 
2652  /*
2653  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
2654  */
2655  relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
2656  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
2657  if (!HeapTupleIsValid(tuple))
2658  elog(ERROR, "cache lookup failed for relation %u", relationId);
2659  classtuple = (Form_pg_class) GETSTRUCT(tuple);
2660 
2661  if (classtuple->relhassubclass != relhassubclass)
2662  {
2663  classtuple->relhassubclass = relhassubclass;
2664  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
2665  }
2666  else
2667  {
2668  /* no need to change tuple, but force relcache rebuild anyway */
2670  }
2671 
2672  heap_freetuple(tuple);
2673  heap_close(relationRelation, RowExclusiveLock);
2674 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
bool relhassubclass
Definition: pg_class.h:63
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#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:1294
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
FormData_pg_class * Form_pg_class
Definition: pg_class.h:93
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1277
#define elog
Definition: elog.h:219