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

12965 {
12966  HeapTuple classTup;
12967  Form_pg_class classForm;
12968  ObjectAddress thisobj;
12969  bool already_done = false;
12970 
12971  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
12972  if (!HeapTupleIsValid(classTup))
12973  elog(ERROR, "cache lookup failed for relation %u", relOid);
12974  classForm = (Form_pg_class) GETSTRUCT(classTup);
12975 
12976  Assert(classForm->relnamespace == oldNspOid);
12977 
12978  thisobj.classId = RelationRelationId;
12979  thisobj.objectId = relOid;
12980  thisobj.objectSubId = 0;
12981 
12982  /*
12983  * If the object has already been moved, don't move it again. If it's
12984  * already in the right place, don't move it, but still fire the object
12985  * access hook.
12986  */
12987  already_done = object_address_present(&thisobj, objsMoved);
12988  if (!already_done && oldNspOid != newNspOid)
12989  {
12990  /* check for duplicate name (more friendly than unique-index failure) */
12991  if (get_relname_relid(NameStr(classForm->relname),
12992  newNspOid) != InvalidOid)
12993  ereport(ERROR,
12994  (errcode(ERRCODE_DUPLICATE_TABLE),
12995  errmsg("relation \"%s\" already exists in schema \"%s\"",
12996  NameStr(classForm->relname),
12997  get_namespace_name(newNspOid))));
12998 
12999  /* classTup is a copy, so OK to scribble on */
13000  classForm->relnamespace = newNspOid;
13001 
13002  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
13003 
13004  /* Update dependency on schema if caller said so */
13005  if (hasDependEntry &&
13006  changeDependencyFor(RelationRelationId,
13007  relOid,
13008  NamespaceRelationId,
13009  oldNspOid,
13010  newNspOid) != 1)
13011  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
13012  NameStr(classForm->relname));
13013  }
13014  if (!already_done)
13015  {
13016  add_exact_object_address(&thisobj, objsMoved);
13017 
13018  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
13019  }
13020 
13021  heap_freetuple(classTup);
13022 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
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:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1687
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h: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:92
#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 3289 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3290 {
3291  Relation rel;
3292 
3293  /* Caller is required to provide an adequate lock. */
3294  rel = relation_open(relid, NoLock);
3295 
3296  CheckTableNotInUse(rel, "ALTER TABLE");
3297 
3298  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode);
3299 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3607
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3208
bool inh
Definition: primnodes.h:70
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 3358 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().

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

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

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

3314 {
3315  Relation rel;
3316  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
3317 
3318  rel = relation_open(relid, lockmode);
3319 
3321 
3322  ATController(NULL, rel, cmds, recurse, lockmode);
3323 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3607
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:3358
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 3238 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3239 {
3240  return RangeVarGetRelidExtended(stmt->relation, lockmode,
3241  stmt->missing_ok ? RVR_MISSING_OK : 0,
3243  (void *) stmt);
3244 }
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:13438
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 11065 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().

11066 {
11067  List *relations = NIL;
11068  ListCell *l;
11069  ScanKeyData key[1];
11070  Relation rel;
11071  HeapScanDesc scan;
11072  HeapTuple tuple;
11073  Oid orig_tablespaceoid;
11074  Oid new_tablespaceoid;
11075  List *role_oids = roleSpecsToIds(stmt->roles);
11076 
11077  /* Ensure we were not asked to move something we can't */
11078  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
11079  stmt->objtype != OBJECT_MATVIEW)
11080  ereport(ERROR,
11081  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
11082  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
11083 
11084  /* Get the orig and new tablespace OIDs */
11085  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
11086  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
11087 
11088  /* Can't move shared relations in to or out of pg_global */
11089  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
11090  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
11091  new_tablespaceoid == GLOBALTABLESPACE_OID)
11092  ereport(ERROR,
11093  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
11094  errmsg("cannot move relations in to or out of pg_global tablespace")));
11095 
11096  /*
11097  * Must have CREATE rights on the new tablespace, unless it is the
11098  * database default tablespace (which all users implicitly have CREATE
11099  * rights on).
11100  */
11101  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
11102  {
11103  AclResult aclresult;
11104 
11105  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
11106  ACL_CREATE);
11107  if (aclresult != ACLCHECK_OK)
11108  aclcheck_error(aclresult, OBJECT_TABLESPACE,
11109  get_tablespace_name(new_tablespaceoid));
11110  }
11111 
11112  /*
11113  * Now that the checks are done, check if we should set either to
11114  * InvalidOid because it is our database's default tablespace.
11115  */
11116  if (orig_tablespaceoid == MyDatabaseTableSpace)
11117  orig_tablespaceoid = InvalidOid;
11118 
11119  if (new_tablespaceoid == MyDatabaseTableSpace)
11120  new_tablespaceoid = InvalidOid;
11121 
11122  /* no-op */
11123  if (orig_tablespaceoid == new_tablespaceoid)
11124  return new_tablespaceoid;
11125 
11126  /*
11127  * Walk the list of objects in the tablespace and move them. This will
11128  * only find objects in our database, of course.
11129  */
11130  ScanKeyInit(&key[0],
11131  Anum_pg_class_reltablespace,
11132  BTEqualStrategyNumber, F_OIDEQ,
11133  ObjectIdGetDatum(orig_tablespaceoid));
11134 
11135  rel = heap_open(RelationRelationId, AccessShareLock);
11136  scan = heap_beginscan_catalog(rel, 1, key);
11137  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
11138  {
11139  Oid relOid = HeapTupleGetOid(tuple);
11140  Form_pg_class relForm;
11141 
11142  relForm = (Form_pg_class) GETSTRUCT(tuple);
11143 
11144  /*
11145  * Do not move objects in pg_catalog as part of this, if an admin
11146  * really wishes to do so, they can issue the individual ALTER
11147  * commands directly.
11148  *
11149  * Also, explicitly avoid any shared tables, temp tables, or TOAST
11150  * (TOAST will be moved with the main table).
11151  */
11152  if (IsSystemNamespace(relForm->relnamespace) || relForm->relisshared ||
11153  isAnyTempNamespace(relForm->relnamespace) ||
11154  relForm->relnamespace == PG_TOAST_NAMESPACE)
11155  continue;
11156 
11157  /* Only move the object type requested */
11158  if ((stmt->objtype == OBJECT_TABLE &&
11159  relForm->relkind != RELKIND_RELATION &&
11160  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
11161  (stmt->objtype == OBJECT_INDEX &&
11162  relForm->relkind != RELKIND_INDEX &&
11163  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
11164  (stmt->objtype == OBJECT_MATVIEW &&
11165  relForm->relkind != RELKIND_MATVIEW))
11166  continue;
11167 
11168  /* Check if we are only moving objects owned by certain roles */
11169  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
11170  continue;
11171 
11172  /*
11173  * Handle permissions-checking here since we are locking the tables
11174  * and also to avoid doing a bunch of work only to fail part-way. Note
11175  * that permissions will also be checked by AlterTableInternal().
11176  *
11177  * Caller must be considered an owner on the table to move it.
11178  */
11179  if (!pg_class_ownercheck(relOid, GetUserId()))
11181  NameStr(relForm->relname));
11182 
11183  if (stmt->nowait &&
11185  ereport(ERROR,
11186  (errcode(ERRCODE_OBJECT_IN_USE),
11187  errmsg("aborting because lock on relation \"%s.%s\" is not available",
11188  get_namespace_name(relForm->relnamespace),
11189  NameStr(relForm->relname))));
11190  else
11192 
11193  /* Add to our list of objects to move */
11194  relations = lappend_oid(relations, relOid);
11195  }
11196 
11197  heap_endscan(scan);
11199 
11200  if (relations == NIL)
11201  ereport(NOTICE,
11202  (errcode(ERRCODE_NO_DATA_FOUND),
11203  errmsg("no matching relations in tablespace \"%s\" found",
11204  orig_tablespaceoid == InvalidOid ? "(database default)" :
11205  get_tablespace_name(orig_tablespaceoid))));
11206 
11207  /* Everything is locked, loop through and move all of the relations. */
11208  foreach(l, relations)
11209  {
11210  List *cmds = NIL;
11212 
11213  cmd->subtype = AT_SetTableSpace;
11214  cmd->name = stmt->new_tablespacename;
11215 
11216  cmds = lappend(cmds, cmd);
11217 
11219  /* OID is set by AlterTableInternal */
11220  AlterTableInternal(lfirst_oid(l), cmds, false);
11222  }
11223 
11224  return new_tablespaceoid;
11225 }
#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:4698
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
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:517
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:88
void EventTriggerAlterTableStart(Node *parsetree)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#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:565
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:4748
FormData_pg_class * Form_pg_class
Definition: pg_class.h:92
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:3313
#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:712
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 12852 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().

12853 {
12854  Relation rel;
12855  Oid relid;
12856  Oid oldNspOid;
12857  Oid nspOid;
12858  RangeVar *newrv;
12859  ObjectAddresses *objsMoved;
12860  ObjectAddress myself;
12861 
12863  stmt->missing_ok ? RVR_MISSING_OK : 0,
12865  (void *) stmt);
12866 
12867  if (!OidIsValid(relid))
12868  {
12869  ereport(NOTICE,
12870  (errmsg("relation \"%s\" does not exist, skipping",
12871  stmt->relation->relname)));
12872  return InvalidObjectAddress;
12873  }
12874 
12875  rel = relation_open(relid, NoLock);
12876 
12877  oldNspOid = RelationGetNamespace(rel);
12878 
12879  /* If it's an owned sequence, disallow moving it by itself. */
12880  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
12881  {
12882  Oid tableId;
12883  int32 colId;
12884 
12885  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
12886  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
12887  ereport(ERROR,
12888  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12889  errmsg("cannot move an owned sequence into another schema"),
12890  errdetail("Sequence \"%s\" is linked to table \"%s\".",
12892  get_rel_name(tableId))));
12893  }
12894 
12895  /* Get and lock schema OID and check its permissions. */
12896  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
12897  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
12898 
12899  /* common checks on switching namespaces */
12900  CheckSetNamespace(oldNspOid, nspOid);
12901 
12902  objsMoved = new_object_addresses();
12903  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
12904  free_object_addresses(objsMoved);
12905 
12906  ObjectAddressSet(myself, RelationRelationId, relid);
12907 
12908  if (oldschema)
12909  *oldschema = oldNspOid;
12910 
12911  /* close rel, but keep lock until commit */
12912  relation_close(rel, NoLock);
12913 
12914  return myself;
12915 }
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:69
#define ERROR
Definition: elog.h:43
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12923
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:13438
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 12923 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().

12925 {
12926  Relation classRel;
12927 
12928  Assert(objsMoved != NULL);
12929 
12930  /* OK, modify the pg_class row and pg_depend entry */
12931  classRel = heap_open(RelationRelationId, RowExclusiveLock);
12932 
12933  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
12934  nspOid, true, objsMoved);
12935 
12936  /* Fix the table's row type too */
12937  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
12938  nspOid, false, false, objsMoved);
12939 
12940  /* Fix other dependent stuff */
12941  if (rel->rd_rel->relkind == RELKIND_RELATION ||
12942  rel->rd_rel->relkind == RELKIND_MATVIEW ||
12943  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12944  {
12945  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
12946  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
12947  objsMoved, AccessExclusiveLock);
12948  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
12949  false, objsMoved);
12950  }
12951 
12952  heap_close(classRel, RowExclusiveLock);
12953 }
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:13031
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:13076
#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:12961
#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 13328 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().

13330 {
13331  ListCell *cur_item;
13332  ListCell *prev_item;
13333 
13334  prev_item = NULL;
13335  cur_item = list_head(on_commits);
13336 
13337  while (cur_item != NULL)
13338  {
13339  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
13340 
13341  if (!isCommit && oc->creating_subid == mySubid)
13342  {
13343  /* cur_item must be removed */
13344  on_commits = list_delete_cell(on_commits, cur_item, prev_item);
13345  pfree(oc);
13346  if (prev_item)
13347  cur_item = lnext(prev_item);
13348  else
13349  cur_item = list_head(on_commits);
13350  }
13351  else
13352  {
13353  /* cur_item must be preserved */
13354  if (oc->creating_subid == mySubid)
13355  oc->creating_subid = parentSubid;
13356  if (oc->deleting_subid == mySubid)
13357  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
13358  prev_item = cur_item;
13359  cur_item = lnext(prev_item);
13360  }
13361  }
13362 }
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 13286 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().

13287 {
13288  ListCell *cur_item;
13289  ListCell *prev_item;
13290 
13291  prev_item = NULL;
13292  cur_item = list_head(on_commits);
13293 
13294  while (cur_item != NULL)
13295  {
13296  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
13297 
13298  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
13300  {
13301  /* cur_item must be removed */
13302  on_commits = list_delete_cell(on_commits, cur_item, prev_item);
13303  pfree(oc);
13304  if (prev_item)
13305  cur_item = lnext(prev_item);
13306  else
13307  cur_item = list_head(on_commits);
13308  }
13309  else
13310  {
13311  /* cur_item must be preserved */
13314  prev_item = cur_item;
13315  cur_item = lnext(prev_item);
13316  }
13317  }
13318 }
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 10241 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().

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

5274 {
5275  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
5276  bool typeOk = false;
5277 
5278  if (typ->typtype == TYPTYPE_COMPOSITE)
5279  {
5280  Relation typeRelation;
5281 
5282  Assert(OidIsValid(typ->typrelid));
5283  typeRelation = relation_open(typ->typrelid, AccessShareLock);
5284  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
5285 
5286  /*
5287  * Close the parent rel, but keep our AccessShareLock on it until xact
5288  * commit. That will prevent someone else from deleting or ALTERing
5289  * the type before the typed table creation/conversion commits.
5290  */
5291  relation_close(typeRelation, NoLock);
5292  }
5293  if (!typeOk)
5294  ereport(ERROR,
5295  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5296  errmsg("type %s is not a composite type",
5297  format_type_be(HeapTupleGetOid(typetuple)))));
5298 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#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:247
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:712

◆ CheckTableNotInUse()

void CheckTableNotInUse ( Relation  rel,
const char *  stmt 
)

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

3209 {
3210  int expected_refcnt;
3211 
3212  expected_refcnt = rel->rd_isnailed ? 2 : 1;
3213  if (rel->rd_refcnt != expected_refcnt)
3214  ereport(ERROR,
3215  (errcode(ERRCODE_OBJECT_IN_USE),
3216  /* translator: first %s is a SQL command, eg ALTER TABLE */
3217  errmsg("cannot %s \"%s\" because "
3218  "it is being used by active queries in this session",
3219  stmt, RelationGetRelationName(rel))));
3220 
3221  if (rel->rd_rel->relkind != RELKIND_INDEX &&
3222  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
3224  ereport(ERROR,
3225  (errcode(ERRCODE_OBJECT_IN_USE),
3226  /* translator: first %s is a SQL command, eg ALTER TABLE */
3227  errmsg("cannot %s \"%s\" because "
3228  "it has pending trigger events",
3229  stmt, RelationGetRelationName(rel))));
3230 }
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:5628
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 8782 of file tablecmds.c.

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

Referenced by ATAddForeignKeyConstraint(), and CloneForeignKeyConstraints().

8784 {
8785  /*
8786  * For the referenced side, create action triggers, if requested. (If the
8787  * referencing side is partitioned, there is still only one trigger, which
8788  * runs on the referenced side and points to the top of the referencing
8789  * hierarchy.)
8790  */
8791  if (create_action)
8792  createForeignKeyActionTriggers(rel, refRelOid, fkconstraint, constraintOid,
8793  indexOid);
8794 
8795  /*
8796  * For the referencing side, create the check triggers. We only need these
8797  * on the partitions.
8798  */
8799  if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
8801  fkconstraint, constraintOid, indexOid);
8802 
8804 }
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:8765
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:8644
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_allows_bound(), 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_allows_bound(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
void check_default_allows_bound(Relation parent, Relation default_rel, PartitionBoundSpec *new_spec)
Definition: partbounds.c:599
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:4698
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:13650
#define OidIsValid(objectId)
Definition: c.h:605
static void StoreCatalogInheritance(Oid relationId, List *supers, bool child_is_partition)
Definition: tablecmds.c:2511
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:13565
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3659
char relkind
Definition: pg_class.h:51
Oid MyDatabaseTableSpace
Definition: globals.c:88
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:69
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
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
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:365
void CommandCounterIncrement(void)
Definition: xact.c:914
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
bool allowSystemTableMods
Definition: globals.c:121
#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:4190
#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:72
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:1832
#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:14487
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:4736
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:70
List * lappend(List *list, void *datum)
Definition: list.c:128
static void truncate_check_rel(Relation rel)
Definition: tablecmds.c:1705
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 decoded.
1638  *
1639  * Assemble an array of relids so we can write a single WAL record for the
1640  * whole action.
1641  */
1642  if (list_length(relids_logged) > 0)
1643  {
1644  xl_heap_truncate xlrec;
1645  int i = 0;
1646 
1647  /* should only get here if wal_level >= logical */
1649 
1650  logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
1651  foreach (cell, relids_logged)
1652  logrelids[i++] = lfirst_oid(cell);
1653 
1654  xlrec.dbId = MyDatabaseId;
1655  xlrec.nrelids = list_length(relids_logged);
1656  xlrec.flags = 0;
1657  if (behavior == DROP_CASCADE)
1658  xlrec.flags |= XLH_TRUNCATE_CASCADE;
1659  if (restart_seqs)
1661 
1662  XLogBeginInsert();
1663  XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
1664  XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
1665 
1667 
1668  (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
1669  }
1670 
1671  /*
1672  * Process all AFTER STATEMENT TRUNCATE triggers.
1673  */
1674  resultRelInfo = resultRelInfos;
1675  foreach(cell, rels)
1676  {
1677  estate->es_result_relation_info = resultRelInfo;
1678  ExecASTruncateTriggers(estate, resultRelInfo);
1679  resultRelInfo++;
1680  }
1681 
1682  /* Handle queued AFTER triggers */
1683  AfterTriggerEndQuery(estate);
1684 
1685  /* We can clean up the EState now */
1686  FreeExecutorState(estate);
1687 
1688  /*
1689  * Close any rels opened by CASCADE (can't do this while EState still
1690  * holds refs)
1691  */
1692  rels = list_difference_ptr(rels, explicit_rels);
1693  foreach(cell, rels)
1694  {
1695  Relation rel = (Relation) lfirst(cell);
1696 
1697  heap_close(rel, NoLock);
1698  }
1699 }
#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:3264
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:3348
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:1705
Oid MyDatabaseId
Definition: globals.c:86
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:4765
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:4748
#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:4785
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:3833
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 5108 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().

5110 {
5111  Relation depRel;
5112  ScanKeyData key[2];
5113  SysScanDesc depScan;
5114  HeapTuple depTup;
5115 
5116  /* since this function recurses, it could be driven to stack overflow */
5118 
5119  /*
5120  * We scan pg_depend to find those things that depend on the given type.
5121  * (We assume we can ignore refobjsubid for a type.)
5122  */
5123  depRel = heap_open(DependRelationId, AccessShareLock);
5124 
5125  ScanKeyInit(&key[0],
5126  Anum_pg_depend_refclassid,
5127  BTEqualStrategyNumber, F_OIDEQ,
5128  ObjectIdGetDatum(TypeRelationId));
5129  ScanKeyInit(&key[1],
5130  Anum_pg_depend_refobjid,
5131  BTEqualStrategyNumber, F_OIDEQ,
5132  ObjectIdGetDatum(typeOid));
5133 
5134  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
5135  NULL, 2, key);
5136 
5137  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
5138  {
5139  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
5140  Relation rel;
5141  Form_pg_attribute att;
5142 
5143  /* Check for directly dependent types */
5144  if (pg_depend->classid == TypeRelationId)
5145  {
5146  /*
5147  * This must be an array, domain, or range containing the given
5148  * type, so recursively check for uses of this type. Note that
5149  * any error message will mention the original type not the
5150  * container; this is intentional.
5151  */
5152  find_composite_type_dependencies(pg_depend->objid,
5153  origRelation, origTypeName);
5154  continue;
5155  }
5156 
5157  /* Else, ignore dependees that aren't user columns of relations */
5158  /* (we assume system columns are never of interesting types) */
5159  if (pg_depend->classid != RelationRelationId ||
5160  pg_depend->objsubid <= 0)
5161  continue;
5162 
5163  rel = relation_open(pg_depend->objid, AccessShareLock);
5164  att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
5165 
5166  if (rel->rd_rel->relkind == RELKIND_RELATION ||
5167  rel->rd_rel->relkind == RELKIND_MATVIEW ||
5168  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5169  {
5170  if (origTypeName)
5171  ereport(ERROR,
5172  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5173  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5174  origTypeName,
5176  NameStr(att->attname))));
5177  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
5178  ereport(ERROR,
5179  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5180  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
5181  RelationGetRelationName(origRelation),
5183  NameStr(att->attname))));
5184  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
5185  ereport(ERROR,
5186  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5187  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
5188  RelationGetRelationName(origRelation),
5190  NameStr(att->attname))));
5191  else
5192  ereport(ERROR,
5193  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5194  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
5195  RelationGetRelationName(origRelation),
5197  NameStr(att->attname))));
5198  }
5199  else if (OidIsValid(rel->rd_rel->reltype))
5200  {
5201  /*
5202  * A view or composite type itself isn't a problem, but we must
5203  * recursively check for indirect dependencies via its rowtype.
5204  */
5206  origRelation, origTypeName);
5207  }
5208 
5210  }
5211 
5212  systable_endscan(depScan);
5213 
5215 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
#define DependReferenceIndexId
Definition: indexing.h:149
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:5108
#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:490
#define ERROR
Definition: elog.h:43
void check_stack_depth(void)
Definition: postgres.c:3155
#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 13865 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_allows_bound(), and QueuePartitionConstraintValidation().

13867 {
13868  List *existConstraint = NIL;
13869  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
13870  int num_check,
13871  i;
13872 
13873  if (constr && constr->has_not_null)
13874  {
13875  int natts = scanrel->rd_att->natts;
13876 
13877  for (i = 1; i <= natts; i++)
13878  {
13879  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
13880 
13881  if (att->attnotnull && !att->attisdropped)
13882  {
13883  NullTest *ntest = makeNode(NullTest);
13884 
13885  ntest->arg = (Expr *) makeVar(1,
13886  i,
13887  att->atttypid,
13888  att->atttypmod,
13889  att->attcollation,
13890  0);
13891  ntest->nulltesttype = IS_NOT_NULL;
13892 
13893  /*
13894  * argisrow=false is correct even for a composite column,
13895  * because attnotnull does not represent a SQL-spec IS NOT
13896  * NULL test in such a case, just IS DISTINCT FROM NULL.
13897  */
13898  ntest->argisrow = false;
13899  ntest->location = -1;
13900  existConstraint = lappend(existConstraint, ntest);
13901  }
13902  }
13903  }
13904 
13905  num_check = (constr != NULL) ? constr->num_check : 0;
13906  for (i = 0; i < num_check; i++)
13907  {
13908  Node *cexpr;
13909 
13910  /*
13911  * If this constraint hasn't been fully validated yet, we must ignore
13912  * it here.
13913  */
13914  if (!constr->check[i].ccvalid)
13915  continue;
13916 
13917  cexpr = stringToNode(constr->check[i].ccbin);
13918 
13919  /*
13920  * Run each expression through const-simplification and
13921  * canonicalization. It is necessary, because we will be comparing it
13922  * to similarly-processed partition constraint expressions, and may
13923  * fail to detect valid matches without this.
13924  */
13925  cexpr = eval_const_expressions(NULL, cexpr);
13926  cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true);
13927 
13928  existConstraint = list_concat(existConstraint,
13929  make_ands_implicit((Expr *) cexpr));
13930  }
13931 
13932  /*
13933  * Try to make the proof. Since we are comparing CHECK constraints, we
13934  * need to use weak implication, i.e., we assume existConstraint is
13935  * not-false and try to prove the same for partConstraint.
13936  *
13937  * Note that predicate_implied_by assumes its first argument is known
13938  * immutable. That should always be true for partition constraints, so we
13939  * don't test it here.
13940  */
13941  return predicate_implied_by(partConstraint, existConstraint, true);
13942 }
#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:517
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:1188
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:1189
#define makeNode(_type_)
Definition: nodes.h:565
int location
Definition: primnodes.h:1191
bool ccvalid
Definition: tupdesc.h:34
int i
bool argisrow
Definition: primnodes.h:1190
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 13215 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().

13216 {
13217  ListCell *l;
13218  List *oids_to_truncate = NIL;
13219 
13220  foreach(l, on_commits)
13221  {
13222  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
13223 
13224  /* Ignore entry if already dropped in this xact */
13226  continue;
13227 
13228  switch (oc->oncommit)
13229  {
13230  case ONCOMMIT_NOOP:
13232  /* Do nothing (there shouldn't be such entries, actually) */
13233  break;
13234  case ONCOMMIT_DELETE_ROWS:
13235 
13236  /*
13237  * If this transaction hasn't accessed any temporary
13238  * relations, we can skip truncating ON COMMIT DELETE ROWS
13239  * tables, as they must still be empty.
13240  */
13242  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
13243  break;
13244  case ONCOMMIT_DROP:
13245  {
13246  ObjectAddress object;
13247 
13248  object.classId = RelationRelationId;
13249  object.objectId = oc->relid;
13250  object.objectSubId = 0;
13251 
13252  /*
13253  * Since this is an automatic drop, rather than one
13254  * directly initiated by the user, we pass the
13255  * PERFORM_DELETION_INTERNAL flag.
13256  */
13257  performDeletion(&object,
13259 
13260  /*
13261  * Note that table deletion will call
13262  * remove_on_commit_action, so the entry should get marked
13263  * as deleted.
13264  */
13266  break;
13267  }
13268  }
13269  }
13270  if (oids_to_truncate != NIL)
13271  {
13272  heap_truncate(oids_to_truncate);
13273  CommandCounterIncrement(); /* XXX needed? */
13274  }
13275 }
#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 13406 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().

13408 {
13409  HeapTuple tuple;
13410 
13411  /* Nothing to do if the relation was not found. */
13412  if (!OidIsValid(relId))
13413  return;
13414 
13415  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
13416  if (!HeapTupleIsValid(tuple)) /* should not happen */
13417  elog(ERROR, "cache lookup failed for relation %u", relId);
13418 
13419  if (!pg_class_ownercheck(relId, GetUserId()))
13421  relation->relname);
13422 
13423  if (!allowSystemTableMods &&
13424  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
13425  ereport(ERROR,
13426  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
13427  errmsg("permission denied: \"%s\" is a system catalog",
13428  relation->relname)));
13429 
13430  ReleaseSysCache(tuple);
13431 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
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:69
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
bool allowSystemTableMods
Definition: globals.c:121
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4748
FormData_pg_class * Form_pg_class
Definition: pg_class.h:92
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 13373 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().

13375 {
13376  char relkind;
13377 
13378  /* Nothing to do if the relation was not found. */
13379  if (!OidIsValid(relId))
13380  return;
13381 
13382  /*
13383  * If the relation does exist, check whether it's an index. But note that
13384  * the relation might have been dropped between the time we did the name
13385  * lookup and now. In that case, there's nothing to do.
13386  */
13387  relkind = get_rel_relkind(relId);
13388  if (!relkind)
13389  return;
13390  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
13391  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
13392  ereport(ERROR,
13393  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13394  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
13395 
13396  /* Check permissions */
13397  if (!pg_class_ownercheck(relId, GetUserId()))
13399 }
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:69
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
#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:4748
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 13161 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().

13162 {
13163  OnCommitItem *oc;
13164  MemoryContext oldcxt;
13165 
13166  /*
13167  * We needn't bother registering the relation unless there is an ON COMMIT
13168  * action we need to take.
13169  */
13171  return;
13172 
13174 
13175  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
13176  oc->relid = relid;
13177  oc->oncommit = action;
13180 
13181  on_commits = lcons(oc, on_commits);
13182 
13183  MemoryContextSwitchTo(oldcxt);
13184 }
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 13192 of file tablecmds.c.

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

Referenced by heap_drop_with_catalog().

13193 {
13194  ListCell *l;
13195 
13196  foreach(l, on_commits)
13197  {
13198  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
13199 
13200  if (oc->relid == relid)
13201  {
13203  break;
13204  }
13205  }
13206 }
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 2879 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().

2880 {
2881  Oid relid;
2883  ObjectAddress address;
2884 
2885  /* lock level taken here should match renameatt_internal */
2887  stmt->missing_ok ? RVR_MISSING_OK : 0,
2889  NULL);
2890 
2891  if (!OidIsValid(relid))
2892  {
2893  ereport(NOTICE,
2894  (errmsg("relation \"%s\" does not exist, skipping",
2895  stmt->relation->relname)));
2896  return InvalidObjectAddress;
2897  }
2898 
2899  attnum =
2900  renameatt_internal(relid,
2901  stmt->subname, /* old att name */
2902  stmt->newname, /* new att name */
2903  stmt->relation->inh, /* recursive? */
2904  false, /* recursing? */
2905  0, /* expected inhcount */
2906  stmt->behavior);
2907 
2908  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
2909 
2910  return address;
2911 }
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:69
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:70
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:2859
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:2714
#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 3016 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().

3017 {
3018  Oid relid = InvalidOid;
3019  Oid typid = InvalidOid;
3020 
3021  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3022  {
3023  Relation rel;
3024  HeapTuple tup;
3025 
3027  rel = heap_open(TypeRelationId, RowExclusiveLock);
3028  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3029  if (!HeapTupleIsValid(tup))
3030  elog(ERROR, "cache lookup failed for type %u", typid);
3031  checkDomainOwner(tup);
3032  ReleaseSysCache(tup);
3033  heap_close(rel, NoLock);
3034  }
3035  else
3036  {
3037  /* lock level taken here should match rename_constraint_internal */
3039  stmt->missing_ok ? RVR_MISSING_OK : 0,
3041  NULL);
3042  if (!OidIsValid(relid))
3043  {
3044  ereport(NOTICE,
3045  (errmsg("relation \"%s\" does not exist, skipping",
3046  stmt->relation->relname)));
3047  return InvalidObjectAddress;
3048  }
3049  }
3050 
3051  return
3052  rename_constraint_internal(relid, typid,
3053  stmt->subname,
3054  stmt->newname,
3055  (stmt->relation &&
3056  stmt->relation->inh), /* recursive? */
3057  false, /* recursing? */
3058  0 /* expected inhcount */ );
3059 
3060 }
char * subname
Definition: parsenodes.h:2847
ObjectType renameType
Definition: parsenodes.h:2843
#define castNode(_type_, nodeptr)
Definition: nodes.h:586
#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:2917
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:69
bool missing_ok
Definition: parsenodes.h:2851
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Node * object
Definition: parsenodes.h: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:70
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:2859
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 3067 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().

3068 {
3069  Oid relid;
3070  ObjectAddress address;
3071 
3072  /*
3073  * Grab an exclusive lock on the target table, index, sequence, view,
3074  * materialized view, or foreign table, which we will NOT release until
3075  * end of transaction.
3076  *
3077  * Lock level used here should match RenameRelationInternal, to avoid lock
3078  * escalation.
3079  */
3081  stmt->missing_ok ? RVR_MISSING_OK : 0,
3083  (void *) stmt);
3084 
3085  if (!OidIsValid(relid))
3086  {
3087  ereport(NOTICE,
3088  (errmsg("relation \"%s\" does not exist, skipping",
3089  stmt->relation->relname)));
3090  return InvalidObjectAddress;
3091  }
3092 
3093  /* Do the work */
3094  RenameRelationInternal(relid, stmt->newname, false);
3095 
3096  ObjectAddressSet(address, RelationRelationId, relid);
3097 
3098  return address;
3099 }
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
Definition: tablecmds.c:3111
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:69
bool missing_ok
Definition: parsenodes.h:2851
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:13438
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 3111 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().

3112 {
3113  Relation targetrelation;
3114  Relation relrelation; /* for RELATION relation */
3115  HeapTuple reltup;
3116  Form_pg_class relform;
3117  Oid namespaceId;
3118 
3119  /*
3120  * Grab an exclusive lock on the target table, index, sequence, view,
3121  * materialized view, or foreign table, which we will NOT release until
3122  * end of transaction.
3123  */
3124  targetrelation = relation_open(myrelid, AccessExclusiveLock);
3125  namespaceId = RelationGetNamespace(targetrelation);
3126 
3127  /*
3128  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3129  */
3130  relrelation = heap_open(RelationRelationId, RowExclusiveLock);
3131 
3132  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3133  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3134  elog(ERROR, "cache lookup failed for relation %u", myrelid);
3135  relform = (Form_pg_class) GETSTRUCT(reltup);
3136 
3137  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3138  ereport(ERROR,
3139  (errcode(ERRCODE_DUPLICATE_TABLE),
3140  errmsg("relation \"%s\" already exists",
3141  newrelname)));
3142 
3143  /*
3144  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
3145  * because it's a copy...)
3146  */
3147  namestrcpy(&(relform->relname), newrelname);
3148 
3149  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3150 
3151  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
3152  InvalidOid, is_internal);
3153 
3154  heap_freetuple(reltup);
3155  heap_close(relrelation, RowExclusiveLock);
3156 
3157  /*
3158  * Also rename the associated type, if any.
3159  */
3160  if (OidIsValid(targetrelation->rd_rel->reltype))
3161  RenameTypeInternal(targetrelation->rd_rel->reltype,
3162  newrelname, namespaceId);
3163 
3164  /*
3165  * Also rename the associated constraint, if any.
3166  */
3167  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3168  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3169  {
3170  Oid constraintId = get_index_constraint(myrelid);
3171 
3172  if (OidIsValid(constraintId))
3173  RenameConstraintById(constraintId, newrelname);
3174  }
3175 
3176  /*
3177  * Close rel, but keep exclusive lock!
3178  */
3179  relation_close(targetrelation, NoLock);
3180 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
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:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1687
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:689
#define ereport(elevel, rest)
Definition: elog.h:122
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:92
#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 2632 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().

2633 {
2634  Relation relationRelation;
2635  HeapTuple tuple;
2636  Form_pg_class classtuple;
2637 
2638  /*
2639  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
2640  */
2641  relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
2642  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
2643  if (!HeapTupleIsValid(tuple))
2644  elog(ERROR, "cache lookup failed for relation %u", relationId);
2645  classtuple = (Form_pg_class) GETSTRUCT(tuple);
2646 
2647  if (classtuple->relhassubclass != relhassubclass)
2648  {
2649  classtuple->relhassubclass = relhassubclass;
2650  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
2651  }
2652  else
2653  {
2654  /* no need to change tuple, but force relcache rebuild anyway */
2656  }
2657 
2658  heap_freetuple(tuple);
2659  heap_close(relationRelation, RowExclusiveLock);
2660 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
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:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c: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:92
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1269
#define elog
Definition: elog.h:219