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 (AlterTableStmt *stmt, LOCKMODE lockmode, struct AlterTableUtilityContext *context)
 
LOCKMODE AlterTableGetLockLevel (List *cmds)
 
void ATExecChangeOwner (Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
 
void AlterTableInternal (Oid relid, List *cmds, bool recurse)
 
Oid AlterTableMoveAll (AlterTableMoveAllStmt *stmt)
 
ObjectAddress AlterTableNamespace (AlterObjectSchemaStmt *stmt, Oid *oldschema)
 
void AlterTableNamespaceInternal (Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
 
void AlterRelationNamespaceInternal (Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
 
void CheckTableNotInUse (Relation rel, const char *stmt)
 
void ExecuteTruncate (TruncateStmt *stmt)
 
void ExecuteTruncateGuts (List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs)
 
void SetRelationHasSubclass (Oid relationId, bool relhassubclass)
 
bool CheckRelationTableSpaceMove (Relation rel, Oid newTableSpaceId)
 
void SetRelationTableSpace (Relation rel, Oid newTableSpaceId, Oid newRelFileNode)
 
ObjectAddress renameatt (RenameStmt *stmt)
 
ObjectAddress RenameConstraint (RenameStmt *stmt)
 
ObjectAddress RenameRelation (RenameStmt *stmt)
 
void RenameRelationInternal (Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
 
void ResetRelRewrite (Oid myrelid)
 
void find_composite_type_dependencies (Oid typeOid, Relation origRelation, const char *origTypeName)
 
void check_of_type (HeapTuple typetuple)
 
void register_on_commit_action (Oid relid, OnCommitAction action)
 
void remove_on_commit_action (Oid relid)
 
void PreCommit_on_commit_actions (void)
 
void AtEOXact_on_commit_actions (bool isCommit)
 
void AtEOSubXact_on_commit_actions (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
void RangeVarCallbackOwnsTable (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
void RangeVarCallbackOwnsRelation (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
bool PartConstraintImpliedByRelConstraint (Relation scanrel, List *partConstraint)
 

Function Documentation

◆ AlterRelationNamespaceInternal()

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

Definition at line 16497 of file tablecmds.c.

16501 {
16502  HeapTuple classTup;
16503  Form_pg_class classForm;
16504  ObjectAddress thisobj;
16505  bool already_done = false;
16506 
16507  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
16508  if (!HeapTupleIsValid(classTup))
16509  elog(ERROR, "cache lookup failed for relation %u", relOid);
16510  classForm = (Form_pg_class) GETSTRUCT(classTup);
16511 
16512  Assert(classForm->relnamespace == oldNspOid);
16513 
16514  thisobj.classId = RelationRelationId;
16515  thisobj.objectId = relOid;
16516  thisobj.objectSubId = 0;
16517 
16518  /*
16519  * If the object has already been moved, don't move it again. If it's
16520  * already in the right place, don't move it, but still fire the object
16521  * access hook.
16522  */
16523  already_done = object_address_present(&thisobj, objsMoved);
16524  if (!already_done && oldNspOid != newNspOid)
16525  {
16526  /* check for duplicate name (more friendly than unique-index failure) */
16527  if (get_relname_relid(NameStr(classForm->relname),
16528  newNspOid) != InvalidOid)
16529  ereport(ERROR,
16530  (errcode(ERRCODE_DUPLICATE_TABLE),
16531  errmsg("relation \"%s\" already exists in schema \"%s\"",
16532  NameStr(classForm->relname),
16533  get_namespace_name(newNspOid))));
16534 
16535  /* classTup is a copy, so OK to scribble on */
16536  classForm->relnamespace = newNspOid;
16537 
16538  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
16539 
16540  /* Update dependency on schema if caller said so */
16541  if (hasDependEntry &&
16542  changeDependencyFor(RelationRelationId,
16543  relOid,
16544  NamespaceRelationId,
16545  oldNspOid,
16546  newNspOid) != 1)
16547  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
16548  NameStr(classForm->relname));
16549  }
16550  if (!already_done)
16551  {
16552  add_exact_object_address(&thisobj, objsMoved);
16553 
16554  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
16555  }
16556 
16557  heap_freetuple(classTup);
16558 }
#define NameStr(name)
Definition: c.h:692
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2562
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2502
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
Assert(fmt[strlen(fmt) - 1] !='\n')
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3326
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1866
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:195
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:399
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define InvalidOid
Definition: postgres_ext.h:36
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
@ RELOID
Definition: syscache.h:89

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

◆ AlterTable()

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

Definition at line 4073 of file tablecmds.c.

4075 {
4076  Relation rel;
4077 
4078  /* Caller is required to provide an adequate lock. */
4079  rel = relation_open(context->relid, NoLock);
4080 
4081  CheckTableNotInUse(rel, "ALTER TABLE");
4082 
4083  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4084 }
#define NoLock
Definition: lockdefs.h:34
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
RangeVar * relation
Definition: parsenodes.h:2219
bool inh
Definition: primnodes.h:77
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3989
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4418

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

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4147 of file tablecmds.c.

4148 {
4149  /*
4150  * This only works if we read catalog tables using MVCC snapshots.
4151  */
4152  ListCell *lcmd;
4154 
4155  foreach(lcmd, cmds)
4156  {
4157  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4158  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4159 
4160  switch (cmd->subtype)
4161  {
4162  /*
4163  * These subcommands rewrite the heap, so require full locks.
4164  */
4165  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4166  * to SELECT */
4167  case AT_SetAccessMethod: /* must rewrite heap */
4168  case AT_SetTableSpace: /* must rewrite heap */
4169  case AT_AlterColumnType: /* must rewrite heap */
4170  cmd_lockmode = AccessExclusiveLock;
4171  break;
4172 
4173  /*
4174  * These subcommands may require addition of toast tables. If
4175  * we add a toast table to a table currently being scanned, we
4176  * might miss data added to the new toast table by concurrent
4177  * insert transactions.
4178  */
4179  case AT_SetStorage: /* may add toast tables, see
4180  * ATRewriteCatalogs() */
4181  cmd_lockmode = AccessExclusiveLock;
4182  break;
4183 
4184  /*
4185  * Removing constraints can affect SELECTs that have been
4186  * optimized assuming the constraint holds true. See also
4187  * CloneFkReferenced.
4188  */
4189  case AT_DropConstraint: /* as DROP INDEX */
4190  case AT_DropNotNull: /* may change some SQL plans */
4191  cmd_lockmode = AccessExclusiveLock;
4192  break;
4193 
4194  /*
4195  * Subcommands that may be visible to concurrent SELECTs
4196  */
4197  case AT_DropColumn: /* change visible to SELECT */
4198  case AT_AddColumnToView: /* CREATE VIEW */
4199  case AT_DropOids: /* used to equiv to DropColumn */
4200  case AT_EnableAlwaysRule: /* may change SELECT rules */
4201  case AT_EnableReplicaRule: /* may change SELECT rules */
4202  case AT_EnableRule: /* may change SELECT rules */
4203  case AT_DisableRule: /* may change SELECT rules */
4204  cmd_lockmode = AccessExclusiveLock;
4205  break;
4206 
4207  /*
4208  * Changing owner may remove implicit SELECT privileges
4209  */
4210  case AT_ChangeOwner: /* change visible to SELECT */
4211  cmd_lockmode = AccessExclusiveLock;
4212  break;
4213 
4214  /*
4215  * Changing foreign table options may affect optimization.
4216  */
4217  case AT_GenericOptions:
4219  cmd_lockmode = AccessExclusiveLock;
4220  break;
4221 
4222  /*
4223  * These subcommands affect write operations only.
4224  */
4225  case AT_EnableTrig:
4226  case AT_EnableAlwaysTrig:
4227  case AT_EnableReplicaTrig:
4228  case AT_EnableTrigAll:
4229  case AT_EnableTrigUser:
4230  case AT_DisableTrig:
4231  case AT_DisableTrigAll:
4232  case AT_DisableTrigUser:
4233  cmd_lockmode = ShareRowExclusiveLock;
4234  break;
4235 
4236  /*
4237  * These subcommands affect write operations only. XXX
4238  * Theoretically, these could be ShareRowExclusiveLock.
4239  */
4240  case AT_ColumnDefault:
4242  case AT_AlterConstraint:
4243  case AT_AddIndex: /* from ADD CONSTRAINT */
4244  case AT_AddIndexConstraint:
4245  case AT_ReplicaIdentity:
4246  case AT_SetNotNull:
4247  case AT_EnableRowSecurity:
4248  case AT_DisableRowSecurity:
4249  case AT_ForceRowSecurity:
4250  case AT_NoForceRowSecurity:
4251  case AT_AddIdentity:
4252  case AT_DropIdentity:
4253  case AT_SetIdentity:
4254  case AT_DropExpression:
4255  case AT_SetCompression:
4256  cmd_lockmode = AccessExclusiveLock;
4257  break;
4258 
4259  case AT_AddConstraint:
4260  case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
4261  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4262  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4263  if (IsA(cmd->def, Constraint))
4264  {
4265  Constraint *con = (Constraint *) cmd->def;
4266 
4267  switch (con->contype)
4268  {
4269  case CONSTR_EXCLUSION:
4270  case CONSTR_PRIMARY:
4271  case CONSTR_UNIQUE:
4272 
4273  /*
4274  * Cases essentially the same as CREATE INDEX. We
4275  * could reduce the lock strength to ShareLock if
4276  * we can work out how to allow concurrent catalog
4277  * updates. XXX Might be set down to
4278  * ShareRowExclusiveLock but requires further
4279  * analysis.
4280  */
4281  cmd_lockmode = AccessExclusiveLock;
4282  break;
4283  case CONSTR_FOREIGN:
4284 
4285  /*
4286  * We add triggers to both tables when we add a
4287  * Foreign Key, so the lock level must be at least
4288  * as strong as CREATE TRIGGER.
4289  */
4290  cmd_lockmode = ShareRowExclusiveLock;
4291  break;
4292 
4293  default:
4294  cmd_lockmode = AccessExclusiveLock;
4295  }
4296  }
4297  break;
4298 
4299  /*
4300  * These subcommands affect inheritance behaviour. Queries
4301  * started before us will continue to see the old inheritance
4302  * behaviour, while queries started after we commit will see
4303  * new behaviour. No need to prevent reads or writes to the
4304  * subtable while we hook it up though. Changing the TupDesc
4305  * may be a problem, so keep highest lock.
4306  */
4307  case AT_AddInherit:
4308  case AT_DropInherit:
4309  cmd_lockmode = AccessExclusiveLock;
4310  break;
4311 
4312  /*
4313  * These subcommands affect implicit row type conversion. They
4314  * have affects similar to CREATE/DROP CAST on queries. don't
4315  * provide for invalidating parse trees as a result of such
4316  * changes, so we keep these at AccessExclusiveLock.
4317  */
4318  case AT_AddOf:
4319  case AT_DropOf:
4320  cmd_lockmode = AccessExclusiveLock;
4321  break;
4322 
4323  /*
4324  * Only used by CREATE OR REPLACE VIEW which must conflict
4325  * with an SELECTs currently using the view.
4326  */
4327  case AT_ReplaceRelOptions:
4328  cmd_lockmode = AccessExclusiveLock;
4329  break;
4330 
4331  /*
4332  * These subcommands affect general strategies for performance
4333  * and maintenance, though don't change the semantic results
4334  * from normal data reads and writes. Delaying an ALTER TABLE
4335  * behind currently active writes only delays the point where
4336  * the new strategy begins to take effect, so there is no
4337  * benefit in waiting. In this case the minimum restriction
4338  * applies: we don't currently allow concurrent catalog
4339  * updates.
4340  */
4341  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4342  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4343  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4344  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4345  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4346  cmd_lockmode = ShareUpdateExclusiveLock;
4347  break;
4348 
4349  case AT_SetLogged:
4350  case AT_SetUnLogged:
4351  cmd_lockmode = AccessExclusiveLock;
4352  break;
4353 
4354  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4355  cmd_lockmode = ShareUpdateExclusiveLock;
4356  break;
4357 
4358  /*
4359  * Rel options are more complex than first appears. Options
4360  * are set here for tables, views and indexes; for historical
4361  * reasons these can all be used with ALTER TABLE, so we can't
4362  * decide between them using the basic grammar.
4363  */
4364  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4365  * getTables() */
4366  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4367  * getTables() */
4368  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4369  break;
4370 
4371  case AT_AttachPartition:
4372  cmd_lockmode = ShareUpdateExclusiveLock;
4373  break;
4374 
4375  case AT_DetachPartition:
4376  if (((PartitionCmd *) cmd->def)->concurrent)
4377  cmd_lockmode = ShareUpdateExclusiveLock;
4378  else
4379  cmd_lockmode = AccessExclusiveLock;
4380  break;
4381 
4383  cmd_lockmode = ShareUpdateExclusiveLock;
4384  break;
4385 
4386  case AT_CheckNotNull:
4387 
4388  /*
4389  * This only examines the table's schema; but lock must be
4390  * strong enough to prevent concurrent DROP NOT NULL.
4391  */
4392  cmd_lockmode = AccessShareLock;
4393  break;
4394 
4395  default: /* oops */
4396  elog(ERROR, "unrecognized alter table type: %d",
4397  (int) cmd->subtype);
4398  break;
4399  }
4400 
4401  /*
4402  * Take the greatest lockmode from any subcommand
4403  */
4404  if (cmd_lockmode > lockmode)
4405  lockmode = cmd_lockmode;
4406  }
4407 
4408  return lockmode;
4409 }
int LOCKMODE
Definition: lockdefs.h:26
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define ShareRowExclusiveLock
Definition: lockdefs.h:41
#define AccessShareLock
Definition: lockdefs.h:36
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define IsA(nodeptr, _type_)
Definition: nodes.h:625
@ CONSTR_FOREIGN
Definition: parsenodes.h:2589
@ CONSTR_UNIQUE
Definition: parsenodes.h:2587
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2588
@ CONSTR_PRIMARY
Definition: parsenodes.h:2586
@ AT_AddIndexConstraint
Definition: parsenodes.h:2252
@ AT_DropOf
Definition: parsenodes.h:2284
@ AT_CheckNotNull
Definition: parsenodes.h:2235
@ AT_SetOptions
Definition: parsenodes.h:2237
@ AT_DropIdentity
Definition: parsenodes.h:2296
@ AT_DisableTrigUser
Definition: parsenodes.h:2276
@ AT_DropNotNull
Definition: parsenodes.h:2232
@ AT_AddOf
Definition: parsenodes.h:2283
@ AT_ResetOptions
Definition: parsenodes.h:2238
@ AT_ReplicaIdentity
Definition: parsenodes.h:2285
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2268
@ AT_EnableRowSecurity
Definition: parsenodes.h:2286
@ AT_AddColumnToView
Definition: parsenodes.h:2229
@ AT_ResetRelOptions
Definition: parsenodes.h:2267
@ AT_AddConstraintRecurse
Definition: parsenodes.h:2246
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2271
@ AT_DropOids
Definition: parsenodes.h:2263
@ AT_SetIdentity
Definition: parsenodes.h:2295
@ AT_SetUnLogged
Definition: parsenodes.h:2262
@ AT_DisableTrig
Definition: parsenodes.h:2272
@ AT_SetCompression
Definition: parsenodes.h:2240
@ AT_DropExpression
Definition: parsenodes.h:2234
@ AT_AddIndex
Definition: parsenodes.h:2243
@ AT_EnableReplicaRule
Definition: parsenodes.h:2279
@ AT_DropConstraint
Definition: parsenodes.h:2253
@ AT_SetNotNull
Definition: parsenodes.h:2233
@ AT_ClusterOn
Definition: parsenodes.h:2259
@ AT_AddIdentity
Definition: parsenodes.h:2294
@ AT_ForceRowSecurity
Definition: parsenodes.h:2288
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2278
@ AT_SetAccessMethod
Definition: parsenodes.h:2264
@ AT_AlterColumnType
Definition: parsenodes.h:2256
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2293
@ AT_AddInherit
Definition: parsenodes.h:2281
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2248
@ AT_EnableTrig
Definition: parsenodes.h:2269
@ AT_DropColumn
Definition: parsenodes.h:2241
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2257
@ AT_DisableTrigAll
Definition: parsenodes.h:2274
@ AT_EnableRule
Definition: parsenodes.h:2277
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2289
@ AT_DetachPartition
Definition: parsenodes.h:2292
@ AT_SetStatistics
Definition: parsenodes.h:2236
@ AT_AttachPartition
Definition: parsenodes.h:2291
@ AT_AddConstraint
Definition: parsenodes.h:2245
@ AT_DropInherit
Definition: parsenodes.h:2282
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2270
@ AT_SetLogged
Definition: parsenodes.h:2261
@ AT_SetStorage
Definition: parsenodes.h:2239
@ AT_DisableRule
Definition: parsenodes.h:2280
@ AT_DisableRowSecurity
Definition: parsenodes.h:2287
@ AT_SetRelOptions
Definition: parsenodes.h:2266
@ AT_ChangeOwner
Definition: parsenodes.h:2258
@ AT_EnableTrigUser
Definition: parsenodes.h:2275
@ AT_ReAddConstraint
Definition: parsenodes.h:2247
@ AT_SetTableSpace
Definition: parsenodes.h:2265
@ AT_GenericOptions
Definition: parsenodes.h:2290
@ AT_ColumnDefault
Definition: parsenodes.h:2230
@ AT_CookedColumnDefault
Definition: parsenodes.h:2231
@ AT_AlterConstraint
Definition: parsenodes.h:2249
@ AT_EnableTrigAll
Definition: parsenodes.h:2273
@ AT_DropCluster
Definition: parsenodes.h:2260
@ AT_ValidateConstraint
Definition: parsenodes.h:2250
@ AT_AddColumn
Definition: parsenodes.h:2227
#define lfirst(lc)
Definition: pg_list.h:170
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2110
AlterTableType subtype
Definition: parsenodes.h:2310
ConstrType contype
Definition: parsenodes.h:2611
Definition: pg_list.h:52

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

Referenced by AlterTableInternal(), and ProcessUtilitySlow().

◆ AlterTableInternal()

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

Definition at line 4102 of file tablecmds.c.

4103 {
4104  Relation rel;
4105  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4106 
4107  rel = relation_open(relid, lockmode);
4108 
4110 
4111  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4112 }
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4147

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4017 of file tablecmds.c.

4018 {
4019  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4020  stmt->missing_ok ? RVR_MISSING_OK : 0,
4022  (void *) stmt);
4023 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:238
@ RVR_MISSING_OK
Definition: namespace.h:71
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:17011

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

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 14471 of file tablecmds.c.

14472 {
14473  List *relations = NIL;
14474  ListCell *l;
14475  ScanKeyData key[1];
14476  Relation rel;
14477  TableScanDesc scan;
14478  HeapTuple tuple;
14479  Oid orig_tablespaceoid;
14480  Oid new_tablespaceoid;
14481  List *role_oids = roleSpecsToIds(stmt->roles);
14482 
14483  /* Ensure we were not asked to move something we can't */
14484  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
14485  stmt->objtype != OBJECT_MATVIEW)
14486  ereport(ERROR,
14487  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14488  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
14489 
14490  /* Get the orig and new tablespace OIDs */
14491  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
14492  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
14493 
14494  /* Can't move shared relations in to or out of pg_global */
14495  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
14496  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
14497  new_tablespaceoid == GLOBALTABLESPACE_OID)
14498  ereport(ERROR,
14499  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14500  errmsg("cannot move relations in to or out of pg_global tablespace")));
14501 
14502  /*
14503  * Must have CREATE rights on the new tablespace, unless it is the
14504  * database default tablespace (which all users implicitly have CREATE
14505  * rights on).
14506  */
14507  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
14508  {
14509  AclResult aclresult;
14510 
14511  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
14512  ACL_CREATE);
14513  if (aclresult != ACLCHECK_OK)
14514  aclcheck_error(aclresult, OBJECT_TABLESPACE,
14515  get_tablespace_name(new_tablespaceoid));
14516  }
14517 
14518  /*
14519  * Now that the checks are done, check if we should set either to
14520  * InvalidOid because it is our database's default tablespace.
14521  */
14522  if (orig_tablespaceoid == MyDatabaseTableSpace)
14523  orig_tablespaceoid = InvalidOid;
14524 
14525  if (new_tablespaceoid == MyDatabaseTableSpace)
14526  new_tablespaceoid = InvalidOid;
14527 
14528  /* no-op */
14529  if (orig_tablespaceoid == new_tablespaceoid)
14530  return new_tablespaceoid;
14531 
14532  /*
14533  * Walk the list of objects in the tablespace and move them. This will
14534  * only find objects in our database, of course.
14535  */
14536  ScanKeyInit(&key[0],
14537  Anum_pg_class_reltablespace,
14538  BTEqualStrategyNumber, F_OIDEQ,
14539  ObjectIdGetDatum(orig_tablespaceoid));
14540 
14541  rel = table_open(RelationRelationId, AccessShareLock);
14542  scan = table_beginscan_catalog(rel, 1, key);
14543  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
14544  {
14545  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
14546  Oid relOid = relForm->oid;
14547 
14548  /*
14549  * Do not move objects in pg_catalog as part of this, if an admin
14550  * really wishes to do so, they can issue the individual ALTER
14551  * commands directly.
14552  *
14553  * Also, explicitly avoid any shared tables, temp tables, or TOAST
14554  * (TOAST will be moved with the main table).
14555  */
14556  if (IsCatalogNamespace(relForm->relnamespace) ||
14557  relForm->relisshared ||
14558  isAnyTempNamespace(relForm->relnamespace) ||
14559  IsToastNamespace(relForm->relnamespace))
14560  continue;
14561 
14562  /* Only move the object type requested */
14563  if ((stmt->objtype == OBJECT_TABLE &&
14564  relForm->relkind != RELKIND_RELATION &&
14565  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
14566  (stmt->objtype == OBJECT_INDEX &&
14567  relForm->relkind != RELKIND_INDEX &&
14568  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
14569  (stmt->objtype == OBJECT_MATVIEW &&
14570  relForm->relkind != RELKIND_MATVIEW))
14571  continue;
14572 
14573  /* Check if we are only moving objects owned by certain roles */
14574  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
14575  continue;
14576 
14577  /*
14578  * Handle permissions-checking here since we are locking the tables
14579  * and also to avoid doing a bunch of work only to fail part-way. Note
14580  * that permissions will also be checked by AlterTableInternal().
14581  *
14582  * Caller must be considered an owner on the table to move it.
14583  */
14584  if (!pg_class_ownercheck(relOid, GetUserId()))
14586  NameStr(relForm->relname));
14587 
14588  if (stmt->nowait &&
14590  ereport(ERROR,
14591  (errcode(ERRCODE_OBJECT_IN_USE),
14592  errmsg("aborting because lock on relation \"%s.%s\" is not available",
14593  get_namespace_name(relForm->relnamespace),
14594  NameStr(relForm->relname))));
14595  else
14597 
14598  /* Add to our list of objects to move */
14599  relations = lappend_oid(relations, relOid);
14600  }
14601 
14602  table_endscan(scan);
14604 
14605  if (relations == NIL)
14606  ereport(NOTICE,
14607  (errcode(ERRCODE_NO_DATA_FOUND),
14608  errmsg("no matching relations in tablespace \"%s\" found",
14609  orig_tablespaceoid == InvalidOid ? "(database default)" :
14610  get_tablespace_name(orig_tablespaceoid))));
14611 
14612  /* Everything is locked, loop through and move all of the relations. */
14613  foreach(l, relations)
14614  {
14615  List *cmds = NIL;
14617 
14618  cmd->subtype = AT_SetTableSpace;
14619  cmd->name = stmt->new_tablespacename;
14620 
14621  cmds = lappend(cmds, cmd);
14622 
14624  /* OID is set by AlterTableInternal */
14625  AlterTableInternal(lfirst_oid(l), cmds, false);
14627  }
14628 
14629  return new_tablespaceoid;
14630 }
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
@ ACLCHECK_NOT_OWNER
Definition: acl.h:184
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:5121
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:5171
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3512
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1520
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1474
#define OidIsValid(objectId)
Definition: c.h:721
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:202
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:184
#define NOTICE
Definition: elog.h:29
void EventTriggerAlterTableStart(Node *parsetree)
void EventTriggerAlterTableEnd(void)
Oid MyDatabaseTableSpace
Definition: globals.c:91
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1296
List * lappend(List *list, void *datum)
Definition: list.c:338
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:721
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:152
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:109
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1984
Oid GetUserId(void)
Definition: miscinit.c:491
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3241
#define makeNode(_type_)
Definition: nodes.h:622
ObjectType get_relkind_objtype(char relkind)
@ OBJECT_MATVIEW
Definition: parsenodes.h:2158
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2177
@ OBJECT_INDEX
Definition: parsenodes.h:2155
@ OBJECT_TABLE
Definition: parsenodes.h:2176
#define ACL_CREATE
Definition: parsenodes.h:91
#define NIL
Definition: pg_list.h:66
#define lfirst_oid(lc)
Definition: pg_list.h:172
unsigned int Oid
Definition: postgres_ext.h:31
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
@ ForwardScanDirection
Definition: sdir.h:26
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Definition: nodes.h:575
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:993
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4102
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1349

References AccessExclusiveLock, AccessShareLock, ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTableInternal(), AT_SetTableSpace, BTEqualStrategyNumber, ConditionalLockRelationOid(), ereport, errcode(), errmsg(), ERROR, EventTriggerAlterTableEnd(), EventTriggerAlterTableStart(), ForwardScanDirection, get_namespace_name(), get_rel_relkind(), get_relkind_objtype(), get_tablespace_name(), get_tablespace_oid(), GETSTRUCT, GetUserId(), heap_getnext(), InvalidOid, isAnyTempNamespace(), IsCatalogNamespace(), IsToastNamespace(), sort-test::key, lappend(), lappend_oid(), lfirst_oid, list_member_oid(), LockRelationOid(), makeNode, MyDatabaseTableSpace, AlterTableCmd::name, NameStr, 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(), AlterTableCmd::subtype, table_beginscan_catalog(), table_close(), table_endscan(), and table_open().

Referenced by ProcessUtilitySlow().

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 16360 of file tablecmds.c.

16361 {
16362  Relation rel;
16363  Oid relid;
16364  Oid oldNspOid;
16365  Oid nspOid;
16366  RangeVar *newrv;
16367  ObjectAddresses *objsMoved;
16368  ObjectAddress myself;
16369 
16371  stmt->missing_ok ? RVR_MISSING_OK : 0,
16373  (void *) stmt);
16374 
16375  if (!OidIsValid(relid))
16376  {
16377  ereport(NOTICE,
16378  (errmsg("relation \"%s\" does not exist, skipping",
16379  stmt->relation->relname)));
16380  return InvalidObjectAddress;
16381  }
16382 
16383  rel = relation_open(relid, NoLock);
16384 
16385  oldNspOid = RelationGetNamespace(rel);
16386 
16387  /* If it's an owned sequence, disallow moving it by itself. */
16388  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
16389  {
16390  Oid tableId;
16391  int32 colId;
16392 
16393  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
16394  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
16395  ereport(ERROR,
16396  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16397  errmsg("cannot move an owned sequence into another schema"),
16398  errdetail("Sequence \"%s\" is linked to table \"%s\".",
16400  get_rel_name(tableId))));
16401  }
16402 
16403  /* Get and lock schema OID and check its permissions. */
16404  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
16405  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
16406 
16407  /*
16408  * Check that setting the relation to a different schema won't result in a
16409  * publication having both a schema and the same schema's table, as this
16410  * is not supported.
16411  */
16412  if (stmt->objectType == OBJECT_TABLE)
16413  {
16414  ListCell *lc;
16415  List *schemaPubids = GetSchemaPublications(nspOid);
16416  List *relPubids = GetRelationPublications(RelationGetRelid(rel));
16417 
16418  foreach(lc, relPubids)
16419  {
16420  Oid pubid = lfirst_oid(lc);
16421 
16422  if (list_member_oid(schemaPubids, pubid))
16423  ereport(ERROR,
16424  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16425  errmsg("cannot move table \"%s\" to schema \"%s\"",
16426  RelationGetRelationName(rel), stmt->newschema),
16427  errdetail("The schema \"%s\" and same schema's table \"%s\" cannot be part of the same publication \"%s\".",
16428  stmt->newschema,
16430  get_publication_name(pubid, false)));
16431  }
16432  }
16433 
16434  /* common checks on switching namespaces */
16435  CheckSetNamespace(oldNspOid, nspOid);
16436 
16437  objsMoved = new_object_addresses();
16438  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
16439  free_object_addresses(objsMoved);
16440 
16441  ObjectAddressSet(myself, RelationRelationId, relid);
16442 
16443  if (oldschema)
16444  *oldschema = oldNspOid;
16445 
16446  /* close rel, but keep lock until commit */
16447  relation_close(rel, NoLock);
16448 
16449  return myself;
16450 }
signed int int32
Definition: c.h:440
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2447
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2742
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int errdetail(const char *fmt,...)
Definition: elog.c:1037
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1909
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:423
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:536
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3013
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:770
List * GetSchemaPublications(Oid schemaid)
List * GetRelationPublications(Oid relid)
char * get_publication_name(Oid pubid, bool missing_ok)
#define RelationGetRelid(relation)
Definition: rel.h:488
#define RelationGetRelationName(relation)
Definition: rel.h:522
#define RelationGetNamespace(relation)
Definition: rel.h:529
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
char * relname
Definition: primnodes.h:74
Form_pg_class rd_rel
Definition: rel.h:109
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16458

References AccessExclusiveLock, AlterTableNamespaceInternal(), CheckSetNamespace(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, ereport, errcode(), errdetail(), errmsg(), ERROR, free_object_addresses(), get_publication_name(), get_rel_name(), GetRelationPublications(), GetSchemaPublications(), InvalidObjectAddress, lfirst_oid, list_member_oid(), makeRangeVar(), AlterObjectSchemaStmt::missing_ok, new_object_addresses(), AlterObjectSchemaStmt::newschema, NoLock, NOTICE, OBJECT_TABLE, ObjectAddressSet, AlterObjectSchemaStmt::objectType, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelidExtended(), RelationData::rd_rel, AlterObjectSchemaStmt::relation, relation_close(), relation_open(), RelationGetNamespace, RelationGetRelationName, RelationGetRelid, RangeVar::relname, RVR_MISSING_OK, and sequenceIsOwned().

Referenced by ExecAlterObjectSchemaStmt().

◆ AlterTableNamespaceInternal()

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

Definition at line 16458 of file tablecmds.c.

16460 {
16461  Relation classRel;
16462 
16463  Assert(objsMoved != NULL);
16464 
16465  /* OK, modify the pg_class row and pg_depend entry */
16466  classRel = table_open(RelationRelationId, RowExclusiveLock);
16467 
16468  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
16469  nspOid, true, objsMoved);
16470 
16471  /* Fix the table's row type too, if it has one */
16472  if (OidIsValid(rel->rd_rel->reltype))
16473  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
16474  nspOid, false, false, objsMoved);
16475 
16476  /* Fix other dependent stuff */
16477  if (rel->rd_rel->relkind == RELKIND_RELATION ||
16478  rel->rd_rel->relkind == RELKIND_MATVIEW ||
16479  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16480  {
16481  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
16482  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
16483  objsMoved, AccessExclusiveLock);
16484  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
16485  false, objsMoved);
16486  }
16487 
16488  table_close(classRel, RowExclusiveLock);
16489 }
#define RowExclusiveLock
Definition: lockdefs.h:38
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16497
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:16612
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16567
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3954

References AccessExclusiveLock, AlterConstraintNamespaces(), AlterIndexNamespaces(), AlterRelationNamespaceInternal(), AlterSeqNamespaces(), AlterTypeNamespaceInternal(), Assert(), OidIsValid, RelationData::rd_rel, RelationGetRelid, RowExclusiveLock, table_close(), and table_open().

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 16888 of file tablecmds.c.

16890 {
16891  ListCell *cur_item;
16892 
16893  foreach(cur_item, on_commits)
16894  {
16895  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16896 
16897  if (!isCommit && oc->creating_subid == mySubid)
16898  {
16899  /* cur_item must be removed */
16901  pfree(oc);
16902  }
16903  else
16904  {
16905  /* cur_item must be preserved */
16906  if (oc->creating_subid == mySubid)
16907  oc->creating_subid = parentSubid;
16908  if (oc->deleting_subid == mySubid)
16909  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
16910  }
16911  }
16912 }
#define InvalidSubTransactionId
Definition: c.h:604
void pfree(void *pointer)
Definition: mcxt.c:1175
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:388
SubTransactionId creating_subid
Definition: tablecmds.c:121
SubTransactionId deleting_subid
Definition: tablecmds.c:122
static List * on_commits
Definition: tablecmds.c:125

References OnCommitItem::creating_subid, OnCommitItem::deleting_subid, foreach_delete_current, InvalidSubTransactionId, lfirst, on_commits, and pfree().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 16856 of file tablecmds.c.

16857 {
16858  ListCell *cur_item;
16859 
16860  foreach(cur_item, on_commits)
16861  {
16862  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16863 
16864  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
16866  {
16867  /* cur_item must be removed */
16869  pfree(oc);
16870  }
16871  else
16872  {
16873  /* cur_item must be preserved */
16876  }
16877  }
16878 }

References OnCommitItem::creating_subid, OnCommitItem::deleting_subid, foreach_delete_current, InvalidSubTransactionId, lfirst, on_commits, and pfree().

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

◆ ATExecChangeOwner()

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

Definition at line 13670 of file tablecmds.c.

13671 {
13672  Relation target_rel;
13673  Relation class_rel;
13674  HeapTuple tuple;
13675  Form_pg_class tuple_class;
13676 
13677  /*
13678  * Get exclusive lock till end of transaction on the target table. Use
13679  * relation_open so that we can work on indexes and sequences.
13680  */
13681  target_rel = relation_open(relationOid, lockmode);
13682 
13683  /* Get its pg_class tuple, too */
13684  class_rel = table_open(RelationRelationId, RowExclusiveLock);
13685 
13686  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relationOid));
13687  if (!HeapTupleIsValid(tuple))
13688  elog(ERROR, "cache lookup failed for relation %u", relationOid);
13689  tuple_class = (Form_pg_class) GETSTRUCT(tuple);
13690 
13691  /* Can we change the ownership of this tuple? */
13692  switch (tuple_class->relkind)
13693  {
13694  case RELKIND_RELATION:
13695  case RELKIND_VIEW:
13696  case RELKIND_MATVIEW:
13697  case RELKIND_FOREIGN_TABLE:
13698  case RELKIND_PARTITIONED_TABLE:
13699  /* ok to change owner */
13700  break;
13701  case RELKIND_INDEX:
13702  if (!recursing)
13703  {
13704  /*
13705  * Because ALTER INDEX OWNER used to be allowed, and in fact
13706  * is generated by old versions of pg_dump, we give a warning
13707  * and do nothing rather than erroring out. Also, to avoid
13708  * unnecessary chatter while restoring those old dumps, say
13709  * nothing at all if the command would be a no-op anyway.
13710  */
13711  if (tuple_class->relowner != newOwnerId)
13712  ereport(WARNING,
13713  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13714  errmsg("cannot change owner of index \"%s\"",
13715  NameStr(tuple_class->relname)),
13716  errhint("Change the ownership of the index's table, instead.")));
13717  /* quick hack to exit via the no-op path */
13718  newOwnerId = tuple_class->relowner;
13719  }
13720  break;
13721  case RELKIND_PARTITIONED_INDEX:
13722  if (recursing)
13723  break;
13724  ereport(ERROR,
13725  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13726  errmsg("cannot change owner of index \"%s\"",
13727  NameStr(tuple_class->relname)),
13728  errhint("Change the ownership of the index's table, instead.")));
13729  break;
13730  case RELKIND_SEQUENCE:
13731  if (!recursing &&
13732  tuple_class->relowner != newOwnerId)
13733  {
13734  /* if it's an owned sequence, disallow changing it by itself */
13735  Oid tableId;
13736  int32 colId;
13737 
13738  if (sequenceIsOwned(relationOid, DEPENDENCY_AUTO, &tableId, &colId) ||
13739  sequenceIsOwned(relationOid, DEPENDENCY_INTERNAL, &tableId, &colId))
13740  ereport(ERROR,
13741  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13742  errmsg("cannot change owner of sequence \"%s\"",
13743  NameStr(tuple_class->relname)),
13744  errdetail("Sequence \"%s\" is linked to table \"%s\".",
13745  NameStr(tuple_class->relname),
13746  get_rel_name(tableId))));
13747  }
13748  break;
13749  case RELKIND_COMPOSITE_TYPE:
13750  if (recursing)
13751  break;
13752  ereport(ERROR,
13753  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13754  errmsg("\"%s\" is a composite type",
13755  NameStr(tuple_class->relname)),
13756  errhint("Use ALTER TYPE instead.")));
13757  break;
13758  case RELKIND_TOASTVALUE:
13759  if (recursing)
13760  break;
13761  /* FALL THRU */
13762  default:
13763  ereport(ERROR,
13764  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
13765  errmsg("cannot change owner of relation \"%s\"",
13766  NameStr(tuple_class->relname)),
13767  errdetail_relkind_not_supported(tuple_class->relkind)));
13768  }
13769 
13770  /*
13771  * If the new owner is the same as the existing owner, consider the
13772  * command to have succeeded. This is for dump restoration purposes.
13773  */
13774  if (tuple_class->relowner != newOwnerId)
13775  {
13776  Datum repl_val[Natts_pg_class];
13777  bool repl_null[Natts_pg_class];
13778  bool repl_repl[Natts_pg_class];
13779  Acl *newAcl;
13780  Datum aclDatum;
13781  bool isNull;
13782  HeapTuple newtuple;
13783 
13784  /* skip permission checks when recursing to index or toast table */
13785  if (!recursing)
13786  {
13787  /* Superusers can always do it */
13788  if (!superuser())
13789  {
13790  Oid namespaceOid = tuple_class->relnamespace;
13791  AclResult aclresult;
13792 
13793  /* Otherwise, must be owner of the existing object */
13794  if (!pg_class_ownercheck(relationOid, GetUserId()))
13796  RelationGetRelationName(target_rel));
13797 
13798  /* Must be able to become new owner */
13799  check_is_member_of_role(GetUserId(), newOwnerId);
13800 
13801  /* New owner must have CREATE privilege on namespace */
13802  aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
13803  ACL_CREATE);
13804  if (aclresult != ACLCHECK_OK)
13805  aclcheck_error(aclresult, OBJECT_SCHEMA,
13806  get_namespace_name(namespaceOid));
13807  }
13808  }
13809 
13810  memset(repl_null, false, sizeof(repl_null));
13811  memset(repl_repl, false, sizeof(repl_repl));
13812 
13813  repl_repl[Anum_pg_class_relowner - 1] = true;
13814  repl_val[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(newOwnerId);
13815 
13816  /*
13817  * Determine the modified ACL for the new owner. This is only
13818  * necessary when the ACL is non-null.
13819  */
13820  aclDatum = SysCacheGetAttr(RELOID, tuple,
13821  Anum_pg_class_relacl,
13822  &isNull);
13823  if (!isNull)
13824  {
13825  newAcl = aclnewowner(DatumGetAclP(aclDatum),
13826  tuple_class->relowner, newOwnerId);
13827  repl_repl[Anum_pg_class_relacl - 1] = true;
13828  repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
13829  }
13830 
13831  newtuple = heap_modify_tuple(tuple, RelationGetDescr(class_rel), repl_val, repl_null, repl_repl);
13832 
13833  CatalogTupleUpdate(class_rel, &newtuple->t_self, newtuple);
13834 
13835  heap_freetuple(newtuple);
13836 
13837  /*
13838  * We must similarly update any per-column ACLs to reflect the new
13839  * owner; for neatness reasons that's split out as a subroutine.
13840  */
13841  change_owner_fix_column_acls(relationOid,
13842  tuple_class->relowner,
13843  newOwnerId);
13844 
13845  /*
13846  * Update owner dependency reference, if any. A composite type has
13847  * none, because it's tracked for the pg_type entry instead of here;
13848  * indexes and TOAST tables don't have their own entries either.
13849  */
13850  if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
13851  tuple_class->relkind != RELKIND_INDEX &&
13852  tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
13853  tuple_class->relkind != RELKIND_TOASTVALUE)
13854  changeDependencyOnOwner(RelationRelationId, relationOid,
13855  newOwnerId);
13856 
13857  /*
13858  * Also change the ownership of the table's row type, if it has one
13859  */
13860  if (OidIsValid(tuple_class->reltype))
13861  AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
13862 
13863  /*
13864  * If we are operating on a table or materialized view, also change
13865  * the ownership of any indexes and sequences that belong to the
13866  * relation, as well as its toast table (if it has one).
13867  */
13868  if (tuple_class->relkind == RELKIND_RELATION ||
13869  tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
13870  tuple_class->relkind == RELKIND_MATVIEW ||
13871  tuple_class->relkind == RELKIND_TOASTVALUE)
13872  {
13873  List *index_oid_list;
13874  ListCell *i;
13875 
13876  /* Find all the indexes belonging to this relation */
13877  index_oid_list = RelationGetIndexList(target_rel);
13878 
13879  /* For each index, recursively change its ownership */
13880  foreach(i, index_oid_list)
13881  ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
13882 
13883  list_free(index_oid_list);
13884  }
13885 
13886  /* If it has a toast table, recurse to change its ownership */
13887  if (tuple_class->reltoastrelid != InvalidOid)
13888  ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
13889  true, lockmode);
13890 
13891  /* If it has dependent sequences, recurse to change them too */
13892  change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
13893  }
13894 
13895  InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
13896 
13897  ReleaseSysCache(tuple);
13898  table_close(class_rel, RowExclusiveLock);
13899  relation_close(target_rel, NoLock);
13900 }
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1052
void check_is_member_of_role(Oid member, Oid role)
Definition: acl.c:4977
#define DatumGetAclP(X)
Definition: acl.h:120
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:5109
int errhint(const char *fmt,...)
Definition: elog.c:1151
#define WARNING
Definition: elog.h:30
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
int i
Definition: isn.c:73
void list_free(List *list)
Definition: list.c:1545
@ OBJECT_SCHEMA
Definition: parsenodes.h:2171
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:312
uintptr_t Datum
Definition: postgres.h:411
#define PointerGetDatum(X)
Definition: postgres.h:600
#define RelationGetDescr(relation)
Definition: rel.h:514
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4675
bool superuser(void)
Definition: superuser.c:46
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1434
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:13670
static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
Definition: tablecmds.c:13974
static void change_owner_fix_column_acls(Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
Definition: tablecmds.c:13909
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3824

References ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, aclnewowner(), AlterTypeOwnerInternal(), CatalogTupleUpdate(), change_owner_fix_column_acls(), change_owner_recurse_to_sequences(), changeDependencyOnOwner(), check_is_member_of_role(), DatumGetAclP, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, elog(), ereport, errcode(), errdetail(), errdetail_relkind_not_supported(), errhint(), errmsg(), ERROR, get_namespace_name(), get_rel_name(), get_rel_relkind(), get_relkind_objtype(), GETSTRUCT, GetUserId(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, i, InvalidOid, InvokeObjectPostAlterHook, lfirst_oid, list_free(), NameStr, NoLock, OBJECT_SCHEMA, ObjectIdGetDatum, OidIsValid, pg_class_ownercheck(), pg_namespace_aclcheck(), PointerGetDatum, relation_close(), relation_open(), RelationGetDescr, RelationGetIndexList(), RelationGetRelationName, ReleaseSysCache(), RELOID, RowExclusiveLock, SearchSysCache1(), sequenceIsOwned(), superuser(), SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), and WARNING.

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

◆ check_of_type()

void check_of_type ( HeapTuple  typetuple)

Definition at line 6581 of file tablecmds.c.

6582 {
6583  Form_pg_type typ = (Form_pg_type) GETSTRUCT(typetuple);
6584  bool typeOk = false;
6585 
6586  if (typ->typtype == TYPTYPE_COMPOSITE)
6587  {
6588  Relation typeRelation;
6589 
6590  Assert(OidIsValid(typ->typrelid));
6591  typeRelation = relation_open(typ->typrelid, AccessShareLock);
6592  typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
6593 
6594  /*
6595  * Close the parent rel, but keep our AccessShareLock on it until xact
6596  * commit. That will prevent someone else from deleting or ALTERing
6597  * the type before the typed table creation/conversion commits.
6598  */
6599  relation_close(typeRelation, NoLock);
6600  }
6601  if (!typeOk)
6602  ereport(ERROR,
6603  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6604  errmsg("type %s is not a composite type",
6605  format_type_be(typ->oid))));
6606 }
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261

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

Referenced by ATExecAddOf(), and transformOfType().

◆ CheckRelationTableSpaceMove()

bool CheckRelationTableSpaceMove ( Relation  rel,
Oid  newTableSpaceId 
)

Definition at line 3275 of file tablecmds.c.

3276 {
3277  Oid oldTableSpaceId;
3278 
3279  /*
3280  * No work if no change in tablespace. Note that MyDatabaseTableSpace is
3281  * stored as 0.
3282  */
3283  oldTableSpaceId = rel->rd_rel->reltablespace;
3284  if (newTableSpaceId == oldTableSpaceId ||
3285  (newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3286  return false;
3287 
3288  /*
3289  * We cannot support moving mapped relations into different tablespaces.
3290  * (In particular this eliminates all shared catalogs.)
3291  */
3292  if (RelationIsMapped(rel))
3293  ereport(ERROR,
3294  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3295  errmsg("cannot move system relation \"%s\"",
3296  RelationGetRelationName(rel))));
3297 
3298  /* Cannot move a non-shared relation into pg_global */
3299  if (newTableSpaceId == GLOBALTABLESPACE_OID)
3300  ereport(ERROR,
3301  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3302  errmsg("only shared relations can be placed in pg_global tablespace")));
3303 
3304  /*
3305  * Do not allow moving temp tables of other backends ... their local
3306  * buffer manager is not going to cope.
3307  */
3308  if (RELATION_IS_OTHER_TEMP(rel))
3309  ereport(ERROR,
3310  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3311  errmsg("cannot move temporary tables of other sessions")));
3312 
3313  return true;
3314 }
#define RelationIsMapped(relation)
Definition: rel.h:537
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:642

References ereport, errcode(), errmsg(), ERROR, MyDatabaseTableSpace, RelationData::rd_rel, RELATION_IS_OTHER_TEMP, RelationGetRelationName, and RelationIsMapped.

Referenced by ATExecSetTableSpace(), ATExecSetTableSpaceNoStorage(), reindex_index(), and SetRelationTableSpace().

◆ CheckTableNotInUse()

void CheckTableNotInUse ( Relation  rel,
const char *  stmt 
)

Definition at line 3989 of file tablecmds.c.

3990 {
3991  int expected_refcnt;
3992 
3993  expected_refcnt = rel->rd_isnailed ? 2 : 1;
3994  if (rel->rd_refcnt != expected_refcnt)
3995  ereport(ERROR,
3996  (errcode(ERRCODE_OBJECT_IN_USE),
3997  /* translator: first %s is a SQL command, eg ALTER TABLE */
3998  errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
3999  stmt, RelationGetRelationName(rel))));
4000 
4001  if (rel->rd_rel->relkind != RELKIND_INDEX &&
4002  rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
4004  ereport(ERROR,
4005  (errcode(ERRCODE_OBJECT_IN_USE),
4006  /* translator: first %s is a SQL command, eg ALTER TABLE */
4007  errmsg("cannot %s \"%s\" because it has pending trigger events",
4008  stmt, RelationGetRelationName(rel))));
4009 }
int rd_refcnt
Definition: rel.h:58
bool rd_isnailed
Definition: rel.h:61
bool AfterTriggerPendingOnRel(Oid relid)
Definition: trigger.c:5912

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

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

◆ DefineRelation()

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

Definition at line 658 of file tablecmds.c.

660 {
661  char relname[NAMEDATALEN];
662  Oid namespaceId;
663  Oid relationId;
664  Oid tablespaceId;
665  Relation rel;
667  List *inheritOids;
668  List *old_constraints;
669  List *rawDefaults;
670  List *cookedDefaults;
671  Datum reloptions;
672  ListCell *listptr;
674  bool partitioned;
675  static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
676  Oid ofTypeId;
677  ObjectAddress address;
678  LOCKMODE parentLockmode;
679  const char *accessMethod = NULL;
680  Oid accessMethodId = InvalidOid;
681 
682  /*
683  * Truncate relname to appropriate length (probably a waste of time, as
684  * parser should have done this already).
685  */
687 
688  /*
689  * Check consistency of arguments
690  */
691  if (stmt->oncommit != ONCOMMIT_NOOP
692  && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
693  ereport(ERROR,
694  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
695  errmsg("ON COMMIT can only be used on temporary tables")));
696 
697  if (stmt->partspec != NULL)
698  {
699  if (relkind != RELKIND_RELATION)
700  elog(ERROR, "unexpected relkind: %d", (int) relkind);
701 
702  relkind = RELKIND_PARTITIONED_TABLE;
703  partitioned = true;
704  }
705  else
706  partitioned = false;
707 
708  /*
709  * Look up the namespace in which we are supposed to create the relation,
710  * check we have permission to create there, lock it against concurrent
711  * drop, and mark stmt->relation as RELPERSISTENCE_TEMP if a temporary
712  * namespace is selected.
713  */
714  namespaceId =
716 
717  /*
718  * Security check: disallow creating temp tables from security-restricted
719  * code. This is needed because calling code might not expect untrusted
720  * tables to appear in pg_temp at the front of its search path.
721  */
722  if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
724  ereport(ERROR,
725  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
726  errmsg("cannot create temporary table within security-restricted operation")));
727 
728  /*
729  * Determine the lockmode to use when scanning parents. A self-exclusive
730  * lock is needed here.
731  *
732  * For regular inheritance, if two backends attempt to add children to the
733  * same parent simultaneously, and that parent has no pre-existing
734  * children, then both will attempt to update the parent's relhassubclass
735  * field, leading to a "tuple concurrently updated" error. Also, this
736  * interlocks against a concurrent ANALYZE on the parent table, which
737  * might otherwise be attempting to clear the parent's relhassubclass
738  * field, if its previous children were recently dropped.
739  *
740  * If the child table is a partition, then we instead grab an exclusive
741  * lock on the parent because its partition descriptor will be changed by
742  * addition of the new partition.
743  */
744  parentLockmode = (stmt->partbound != NULL ? AccessExclusiveLock :
746 
747  /* Determine the list of OIDs of the parents. */
748  inheritOids = NIL;
749  foreach(listptr, stmt->inhRelations)
750  {
751  RangeVar *rv = (RangeVar *) lfirst(listptr);
752  Oid parentOid;
753 
754  parentOid = RangeVarGetRelid(rv, parentLockmode, false);
755 
756  /*
757  * Reject duplications in the list of parents.
758  */
759  if (list_member_oid(inheritOids, parentOid))
760  ereport(ERROR,
761  (errcode(ERRCODE_DUPLICATE_TABLE),
762  errmsg("relation \"%s\" would be inherited from more than once",
763  get_rel_name(parentOid))));
764 
765  inheritOids = lappend_oid(inheritOids, parentOid);
766  }
767 
768  /*
769  * Select tablespace to use: an explicitly indicated one, or (in the case
770  * of a partitioned table) the parent's, if it has one.
771  */
772  if (stmt->tablespacename)
773  {
774  tablespaceId = get_tablespace_oid(stmt->tablespacename, false);
775 
776  if (partitioned && tablespaceId == MyDatabaseTableSpace)
777  ereport(ERROR,
778  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
779  errmsg("cannot specify default tablespace for partitioned relations")));
780  }
781  else if (stmt->partbound)
782  {
783  /*
784  * For partitions, when no other tablespace is specified, we default
785  * the tablespace to the parent partitioned table's.
786  */
787  Assert(list_length(inheritOids) == 1);
788  tablespaceId = get_rel_tablespace(linitial_oid(inheritOids));
789  }
790  else
791  tablespaceId = InvalidOid;
792 
793  /* still nothing? use the default */
794  if (!OidIsValid(tablespaceId))
795  tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence,
796  partitioned);
797 
798  /* Check permissions except when using database's default */
799  if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
800  {
801  AclResult aclresult;
802 
803  aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
804  ACL_CREATE);
805  if (aclresult != ACLCHECK_OK)
807  get_tablespace_name(tablespaceId));
808  }
809 
810  /* In all cases disallow placing user relations in pg_global */
811  if (tablespaceId == GLOBALTABLESPACE_OID)
812  ereport(ERROR,
813  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
814  errmsg("only shared relations can be placed in pg_global tablespace")));
815 
816  /* Identify user ID that will own the table */
817  if (!OidIsValid(ownerId))
818  ownerId = GetUserId();
819 
820  /*
821  * Parse and validate reloptions, if any.
822  */
823  reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
824  true, false);
825 
826  switch (relkind)
827  {
828  case RELKIND_VIEW:
829  (void) view_reloptions(reloptions, true);
830  break;
831  case RELKIND_PARTITIONED_TABLE:
832  (void) partitioned_table_reloptions(reloptions, true);
833  break;
834  default:
835  (void) heap_reloptions(relkind, reloptions, true);
836  }
837 
838  if (stmt->ofTypename)
839  {
840  AclResult aclresult;
841 
842  ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
843 
844  aclresult = pg_type_aclcheck(ofTypeId, GetUserId(), ACL_USAGE);
845  if (aclresult != ACLCHECK_OK)
846  aclcheck_error_type(aclresult, ofTypeId);
847  }
848  else
849  ofTypeId = InvalidOid;
850 
851  /*
852  * Look up inheritance ancestors and generate relation schema, including
853  * inherited attributes. (Note that stmt->tableElts is destructively
854  * modified by MergeAttributes.)
855  */
856  stmt->tableElts =
857  MergeAttributes(stmt->tableElts, inheritOids,
858  stmt->relation->relpersistence,
859  stmt->partbound != NULL,
860  &old_constraints);
861 
862  /*
863  * Create a tuple descriptor from the relation schema. Note that this
864  * deals with column names, types, and NOT NULL constraints, but not
865  * default values or CHECK constraints; we handle those below.
866  */
868 
869  /*
870  * Find columns with default values and prepare for insertion of the
871  * defaults. Pre-cooked (that is, inherited) defaults go into a list of
872  * CookedConstraint structs that we'll pass to heap_create_with_catalog,
873  * while raw defaults go into a list of RawColumnDefault structs that will
874  * be processed by AddRelationNewConstraints. (We can't deal with raw
875  * expressions until we can do transformExpr.)
876  *
877  * We can set the atthasdef flags now in the tuple descriptor; this just
878  * saves StoreAttrDefault from having to do an immediate update of the
879  * pg_attribute rows.
880  */
881  rawDefaults = NIL;
882  cookedDefaults = NIL;
883  attnum = 0;
884 
885  foreach(listptr, stmt->tableElts)
886  {
887  ColumnDef *colDef = lfirst(listptr);
888  Form_pg_attribute attr;
889 
890  attnum++;
891  attr = TupleDescAttr(descriptor, attnum - 1);
892 
893  if (colDef->raw_default != NULL)
894  {
895  RawColumnDefault *rawEnt;
896 
897  Assert(colDef->cooked_default == NULL);
898 
899  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
900  rawEnt->attnum = attnum;
901  rawEnt->raw_default = colDef->raw_default;
902  rawEnt->missingMode = false;
903  rawEnt->generated = colDef->generated;
904  rawDefaults = lappend(rawDefaults, rawEnt);
905  attr->atthasdef = true;
906  }
907  else if (colDef->cooked_default != NULL)
908  {
909  CookedConstraint *cooked;
910 
911  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
912  cooked->contype = CONSTR_DEFAULT;
913  cooked->conoid = InvalidOid; /* until created */
914  cooked->name = NULL;
915  cooked->attnum = attnum;
916  cooked->expr = colDef->cooked_default;
917  cooked->skip_validation = false;
918  cooked->is_local = true; /* not used for defaults */
919  cooked->inhcount = 0; /* ditto */
920  cooked->is_no_inherit = false;
921  cookedDefaults = lappend(cookedDefaults, cooked);
922  attr->atthasdef = true;
923  }
924 
925  if (colDef->identity)
926  attr->attidentity = colDef->identity;
927 
928  if (colDef->generated)
929  attr->attgenerated = colDef->generated;
930 
931  if (colDef->compression)
932  attr->attcompression = GetAttributeCompression(attr->atttypid,
933  colDef->compression);
934  }
935 
936  /*
937  * If the statement hasn't specified an access method, but we're defining
938  * a type of relation that needs one, use the default.
939  */
940  if (stmt->accessMethod != NULL)
941  {
942  accessMethod = stmt->accessMethod;
943 
944  if (partitioned)
945  ereport(ERROR,
946  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
947  errmsg("specifying a table access method is not supported on a partitioned table")));
948  }
949  else if (RELKIND_HAS_TABLE_AM(relkind))
950  accessMethod = default_table_access_method;
951 
952  /* look up the access method, verify it is for a table */
953  if (accessMethod != NULL)
954  accessMethodId = get_table_am_oid(accessMethod, false);
955 
956  /*
957  * Create the relation. Inherited defaults and constraints are passed in
958  * for immediate handling --- since they don't need parsing, they can be
959  * stored immediately.
960  */
961  relationId = heap_create_with_catalog(relname,
962  namespaceId,
963  tablespaceId,
964  InvalidOid,
965  InvalidOid,
966  ofTypeId,
967  ownerId,
968  accessMethodId,
969  descriptor,
970  list_concat(cookedDefaults,
971  old_constraints),
972  relkind,
973  stmt->relation->relpersistence,
974  false,
975  false,
976  stmt->oncommit,
977  reloptions,
978  true,
980  false,
981  InvalidOid,
982  typaddress);
983 
984  /*
985  * We must bump the command counter to make the newly-created relation
986  * tuple visible for opening.
987  */
989 
990  /*
991  * Open the new relation and acquire exclusive lock on it. This isn't
992  * really necessary for locking out other backends (since they can't see
993  * the new rel anyway until we commit), but it keeps the lock manager from
994  * complaining about deadlock risks.
995  */
996  rel = relation_open(relationId, AccessExclusiveLock);
997 
998  /*
999  * Now add any newly specified column default and generation expressions
1000  * to the new relation. These are passed to us in the form of raw
1001  * parsetrees; we need to transform them to executable expression trees
1002  * before they can be added. The most convenient way to do that is to
1003  * apply the parser's transformExpr routine, but transformExpr doesn't
1004  * work unless we have a pre-existing relation. So, the transformation has
1005  * to be postponed to this final step of CREATE TABLE.
1006  *
1007  * This needs to be before processing the partitioning clauses because
1008  * those could refer to generated columns.
1009  */
1010  if (rawDefaults)
1011  AddRelationNewConstraints(rel, rawDefaults, NIL,
1012  true, true, false, queryString);
1013 
1014  /*
1015  * Make column generation expressions visible for use by partitioning.
1016  */
1018 
1019  /* Process and store partition bound, if any. */
1020  if (stmt->partbound)
1021  {
1022  PartitionBoundSpec *bound;
1023  ParseState *pstate;
1024  Oid parentId = linitial_oid(inheritOids),
1025  defaultPartOid;
1026  Relation parent,
1027  defaultRel = NULL;
1028  ParseNamespaceItem *nsitem;
1029 
1030  /* Already have strong enough lock on the parent */
1031  parent = table_open(parentId, NoLock);
1032 
1033  /*
1034  * We are going to try to validate the partition bound specification
1035  * against the partition key of parentRel, so it better have one.
1036  */
1037  if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1038  ereport(ERROR,
1039  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1040  errmsg("\"%s\" is not partitioned",
1041  RelationGetRelationName(parent))));
1042 
1043  /*
1044  * The partition constraint of the default partition depends on the
1045  * partition bounds of every other partition. It is possible that
1046  * another backend might be about to execute a query on the default
1047  * partition table, and that the query relies on previously cached
1048  * default partition constraints. We must therefore take a table lock
1049  * strong enough to prevent all queries on the default partition from
1050  * proceeding until we commit and send out a shared-cache-inval notice
1051  * that will make them update their index lists.
1052  *
1053  * Order of locking: The relation being added won't be visible to
1054  * other backends until it is committed, hence here in
1055  * DefineRelation() the order of locking the default partition and the
1056  * relation being added does not matter. But at all other places we
1057  * need to lock the default relation before we lock the relation being
1058  * added or removed i.e. we should take the lock in same order at all
1059  * the places such that lock parent, lock default partition and then
1060  * lock the partition so as to avoid a deadlock.
1061  */
1062  defaultPartOid =
1064  true));
1065  if (OidIsValid(defaultPartOid))
1066  defaultRel = table_open(defaultPartOid, AccessExclusiveLock);
1067 
1068  /* Transform the bound values */
1069  pstate = make_parsestate(NULL);
1070  pstate->p_sourcetext = queryString;
1071 
1072  /*
1073  * Add an nsitem containing this relation, so that transformExpr
1074  * called on partition bound expressions is able to report errors
1075  * using a proper context.
1076  */
1077  nsitem = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
1078  NULL, false, false);
1079  addNSItemToQuery(pstate, nsitem, false, true, true);
1080 
1081  bound = transformPartitionBound(pstate, parent, stmt->partbound);
1082 
1083  /*
1084  * Check first that the new partition's bound is valid and does not
1085  * overlap with any of existing partitions of the parent.
1086  */
1087  check_new_partition_bound(relname, parent, bound, pstate);
1088 
1089  /*
1090  * If the default partition exists, its partition constraints will
1091  * change after the addition of this new partition such that it won't
1092  * allow any row that qualifies for this new partition. So, check that
1093  * the existing data in the default partition satisfies the constraint
1094  * as it will exist after adding this partition.
1095  */
1096  if (OidIsValid(defaultPartOid))
1097  {
1098  check_default_partition_contents(parent, defaultRel, bound);
1099  /* Keep the lock until commit. */
1100  table_close(defaultRel, NoLock);
1101  }
1102 
1103  /* Update the pg_class entry. */
1104  StorePartitionBound(rel, parent, bound);
1105 
1106  table_close(parent, NoLock);
1107  }
1108 
1109  /* Store inheritance information for new rel. */
1110  StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL);
1111 
1112  /*
1113  * Process the partitioning specification (if any) and store the partition
1114  * key information into the catalog.
1115  */
1116  if (partitioned)
1117  {
1118  ParseState *pstate;
1119  char strategy;
1120  int partnatts;
1121  AttrNumber partattrs[PARTITION_MAX_KEYS];
1122  Oid partopclass[PARTITION_MAX_KEYS];
1123  Oid partcollation[PARTITION_MAX_KEYS];
1124  List *partexprs = NIL;
1125 
1126  pstate = make_parsestate(NULL);
1127  pstate->p_sourcetext = queryString;
1128 
1129  partnatts = list_length(stmt->partspec->partParams);
1130 
1131  /* Protect fixed-size arrays here and in executor */
1132  if (partnatts > PARTITION_MAX_KEYS)
1133  ereport(ERROR,
1134  (errcode(ERRCODE_TOO_MANY_COLUMNS),
1135  errmsg("cannot partition using more than %d columns",
1136  PARTITION_MAX_KEYS)));
1137 
1138  /*
1139  * We need to transform the raw parsetrees corresponding to partition
1140  * expressions into executable expression trees. Like column defaults
1141  * and CHECK constraints, we could not have done the transformation
1142  * earlier.
1143  */
1144  stmt->partspec = transformPartitionSpec(rel, stmt->partspec,
1145  &strategy);
1146 
1147  ComputePartitionAttrs(pstate, rel, stmt->partspec->partParams,
1148  partattrs, &partexprs, partopclass,
1149  partcollation, strategy);
1150 
1151  StorePartitionKey(rel, strategy, partnatts, partattrs, partexprs,
1152  partopclass, partcollation);
1153 
1154  /* make it all visible */
1156  }
1157 
1158  /*
1159  * If we're creating a partition, create now all the indexes, triggers,
1160  * FKs defined in the parent.
1161  *
1162  * We can't do it earlier, because DefineIndex wants to know the partition
1163  * key which we just stored.
1164  */
1165  if (stmt->partbound)
1166  {
1167  Oid parentId = linitial_oid(inheritOids);
1168  Relation parent;
1169  List *idxlist;
1170  ListCell *cell;
1171 
1172  /* Already have strong enough lock on the parent */
1173  parent = table_open(parentId, NoLock);
1174  idxlist = RelationGetIndexList(parent);
1175 
1176  /*
1177  * For each index in the parent table, create one in the partition
1178  */
1179  foreach(cell, idxlist)
1180  {
1181  Relation idxRel = index_open(lfirst_oid(cell), AccessShareLock);
1182  AttrMap *attmap;
1183  IndexStmt *idxstmt;
1184  Oid constraintOid;
1185 
1186  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1187  {
1188  if (idxRel->rd_index->indisunique)
1189  ereport(ERROR,
1190  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1191  errmsg("cannot create foreign partition of partitioned table \"%s\"",
1192  RelationGetRelationName(parent)),
1193  errdetail("Table \"%s\" contains indexes that are unique.",
1194  RelationGetRelationName(parent))));
1195  else
1196  {
1197  index_close(idxRel, AccessShareLock);
1198  continue;
1199  }
1200  }
1201 
1203  RelationGetDescr(parent));
1204  idxstmt =
1205  generateClonedIndexStmt(NULL, idxRel,
1206  attmap, &constraintOid);
1208  idxstmt,
1209  InvalidOid,
1210  RelationGetRelid(idxRel),
1211  constraintOid,
1212  false, false, false, false, false);
1213 
1214  index_close(idxRel, AccessShareLock);
1215  }
1216 
1217  list_free(idxlist);
1218 
1219  /*
1220  * If there are any row-level triggers, clone them to the new
1221  * partition.
1222  */
1223  if (parent->trigdesc != NULL)
1224  CloneRowTriggersToPartition(parent, rel);
1225 
1226  /*
1227  * And foreign keys too. Note that because we're freshly creating the
1228  * table, there is no need to verify these new constraints.
1229  */
1230  CloneForeignKeyConstraints(NULL, parent, rel);
1231 
1232  table_close(parent, NoLock);
1233  }
1234 
1235  /*
1236  * Now add any newly specified CHECK constraints to the new relation. Same
1237  * as for defaults above, but these need to come after partitioning is set
1238  * up.
1239  */
1240  if (stmt->constraints)
1242  true, true, false, queryString);
1243 
1244  ObjectAddressSet(address, RelationRelationId, relationId);
1245 
1246  /*
1247  * Clean up. We keep lock on new relation (although it shouldn't be
1248  * visible to anyone else anyway, until commit).
1249  */
1250  relation_close(rel, NoLock);
1251 
1252  return address;
1253 }
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:5159
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3831
Oid get_table_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:173
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:174
int16 AttrNumber
Definition: attnum.h:21
Oid GetDefaultTablespace(char relpersistence, bool partitioned)
Definition: tablespace.c:1191
bool allowSystemTableMods
Definition: globals.c:124
void StorePartitionKey(Relation rel, char strategy, int16 partnatts, AttrNumber *partattrs, List *partexprs, Oid *partopclass, Oid *partcollation)
Definition: heap.c:3308
Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, Oid reltypeid, Oid reloftypeid, Oid ownerid, Oid accessmtd, TupleDesc tupdesc, List *cooked_constraints, char relkind, char relpersistence, bool shared_relation, bool mapped_relation, OnCommitAction oncommit, Datum reloptions, bool use_user_acl, bool allow_system_table_mods, bool is_internal, Oid relrewrite, ObjectAddress *typaddress)
Definition: heap.c:1088
void StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound)
Definition: heap.c:3466
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2254
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
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:521
List * list_concat(List *list1, const List *list2)
Definition: list.c:560
Oid get_rel_tablespace(Oid relid)
Definition: lsyscache.c:2035
void * palloc(Size size)
Definition: mcxt.c:1068
bool InSecurityRestrictedOperation(void)
Definition: miscinit.c:629
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:79
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
IndexStmt * generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, const AttrMap *attmap, Oid *constraintOid)
PartitionBoundSpec * transformPartitionBound(ParseState *pstate, Relation parent, PartitionBoundSpec *spec)
#define ACL_USAGE
Definition: parsenodes.h:90
@ CONSTR_DEFAULT
Definition: parsenodes.h:2582
void check_new_partition_bound(char *relname, Relation parent, PartitionBoundSpec *spec, ParseState *pstate)
Definition: partbounds.c:2908
void check_default_partition_contents(Relation parent, Relation default_rel, PartitionBoundSpec *new_spec)
Definition: partbounds.c:3267
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:72
Oid get_default_oid_from_partdesc(PartitionDesc partdesc)
Definition: partdesc.c:455
int16 attnum
Definition: pg_attribute.h:83
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
NameData relname
Definition: pg_class.h:38
#define PARTITION_MAX_KEYS
#define NAMEDATALEN
static int list_length(const List *l)
Definition: pg_list.h:150
#define linitial_oid(l)
Definition: pg_list.h:178
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
@ ONCOMMIT_NOOP
Definition: primnodes.h:49
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, char *validnsps[], bool acceptOidsOff, bool isReset)
Definition: reloptions.c:1158
bytea * heap_reloptions(char relkind, Datum reloptions, bool validate)
Definition: reloptions.c:2021
bytea * view_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:2000
bytea * partitioned_table_reloptions(Datum reloptions, bool validate)
Definition: reloptions.c:1985
#define HEAP_RELOPT_NAMESPACES
Definition: reloptions.h:61
Definition: attmap.h:35
char identity
Definition: parsenodes.h:688
Node * cooked_default
Definition: parsenodes.h:687
char generated
Definition: parsenodes.h:691
Node * raw_default
Definition: parsenodes.h:686
char * compression
Definition: parsenodes.h:680
Oid conoid
Definition: heap.h:38
char * name
Definition: heap.h:39
AttrNumber attnum
Definition: heap.h:40
bool skip_validation
Definition: heap.h:42
bool is_no_inherit
Definition: heap.h:45
int inhcount
Definition: heap.h:44
bool is_local
Definition: heap.h:43
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:41
List * tableElts
Definition: parsenodes.h:2532
TypeName * ofTypename
Definition: parsenodes.h:2537
OnCommitAction oncommit
Definition: parsenodes.h:2540
List * options
Definition: parsenodes.h:2539
List * inhRelations
Definition: parsenodes.h:2533
RangeVar * relation
Definition: parsenodes.h:2531
char * tablespacename
Definition: parsenodes.h:2541
PartitionSpec * partspec
Definition: parsenodes.h:2536
PartitionBoundSpec * partbound
Definition: parsenodes.h:2535
char * accessMethod
Definition: parsenodes.h:2542
List * constraints
Definition: parsenodes.h:2538
const char * p_sourcetext
Definition: parse_node.h:182
List * partParams
Definition: parsenodes.h:830
char relpersistence
Definition: primnodes.h:80
Node * raw_default
Definition: heap.h:30
AttrNumber attnum
Definition: heap.h:29
char generated
Definition: heap.h:32
bool missingMode
Definition: heap.h:31
TriggerDesc * trigdesc
Definition: rel.h:115
Form_pg_index rd_index
Definition: rel.h:187
char * default_table_access_method
Definition: tableam.c:48
static PartitionSpec * transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
Definition: tablecmds.c:17148
static char GetAttributeCompression(Oid atttypid, char *compression)
Definition: tablecmds.c:19258
static List * MergeAttributes(List *schema, List *supers, char relpersistence, bool is_partition, List **supconstr)
Definition: tablecmds.c:2313
static void CloneRowTriggersToPartition(Relation parent, Relation partition)
Definition: tablecmds.c:18137
static void ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, char strategy)
Definition: tablecmds.c:17219
static void StoreCatalogInheritance(Oid relationId, List *supers, bool child_is_partition)
Definition: tablecmds.c:3113
static void CloneForeignKeyConstraints(List **wqueue, Relation parentRel, Relation partitionRel)
Definition: tablecmds.c:9949
TupleDesc BuildDescForRelation(List *schema)
Definition: tupdesc.c:786
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
void CommandCounterIncrement(void)
Definition: xact.c:1074

References AccessExclusiveLock, CreateStmt::accessMethod, AccessShareLock, ACL_CREATE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, addNSItemToQuery(), addRangeTableEntryForRelation(), AddRelationNewConstraints(), allowSystemTableMods, Assert(), RawColumnDefault::attnum, CookedConstraint::attnum, attnum, build_attrmap_by_name(), BuildDescForRelation(), check_default_partition_contents(), check_new_partition_bound(), CloneForeignKeyConstraints(), CloneRowTriggersToPartition(), CommandCounterIncrement(), ColumnDef::compression, ComputePartitionAttrs(), CookedConstraint::conoid, CONSTR_DEFAULT, CreateStmt::constraints, CookedConstraint::contype, ColumnDef::cooked_default, default_table_access_method, DefineIndex(), elog(), ereport, errcode(), errdetail(), errmsg(), ERROR, CookedConstraint::expr, generateClonedIndexStmt(), RawColumnDefault::generated, ColumnDef::generated, get_default_oid_from_partdesc(), get_rel_name(), get_rel_tablespace(), get_table_am_oid(), get_tablespace_name(), get_tablespace_oid(), GetAttributeCompression(), GetDefaultTablespace(), GetUserId(), heap_create_with_catalog(), HEAP_RELOPT_NAMESPACES, heap_reloptions(), ColumnDef::identity, index_close(), index_open(), CookedConstraint::inhcount, CreateStmt::inhRelations, InSecurityRestrictedOperation(), InvalidOid, CookedConstraint::is_local, CookedConstraint::is_no_inherit, lappend(), lappend_oid(), lfirst, lfirst_oid, linitial_oid, list_concat(), list_free(), list_length(), list_member_oid(), make_parsestate(), MergeAttributes(), RawColumnDefault::missingMode, MyDatabaseTableSpace, CookedConstraint::name, NAMEDATALEN, NIL, NoLock, OBJECT_TABLESPACE, ObjectAddressSet, CreateStmt::ofTypename, OidIsValid, CreateStmt::oncommit, ONCOMMIT_NOOP, CreateStmt::options, ParseState::p_sourcetext, palloc(), CreateStmt::partbound, PARTITION_MAX_KEYS, partitioned_table_reloptions(), PartitionSpec::partParams, CreateStmt::partspec, pg_tablespace_aclcheck(), pg_type_aclcheck(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelid, RawColumnDefault::raw_default, ColumnDef::raw_default, RelationData::rd_index, RelationData::rd_rel, CreateStmt::relation, relation_close(), relation_open(), RelationGetDescr, RelationGetIndexList(), RelationGetPartitionDesc(), RelationGetRelationName, RelationGetRelid, relname, RangeVar::relname, RangeVar::relpersistence, ShareUpdateExclusiveLock, CookedConstraint::skip_validation, StoreCatalogInheritance(), StorePartitionBound(), StorePartitionKey(), strlcpy(), table_close(), table_open(), CreateStmt::tableElts, CreateStmt::tablespacename, transformPartitionBound(), transformPartitionSpec(), transformRelOptions(), RelationData::trigdesc, TupleDescAttr, typenameTypeId(), and view_reloptions().

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

◆ ExecuteTruncate()

void ExecuteTruncate ( TruncateStmt stmt)

Definition at line 1658 of file tablecmds.c.

1659 {
1660  List *rels = NIL;
1661  List *relids = NIL;
1662  List *relids_logged = NIL;
1663  ListCell *cell;
1664 
1665  /*
1666  * Open, exclusive-lock, and check all the explicitly-specified relations
1667  */
1668  foreach(cell, stmt->relations)
1669  {
1670  RangeVar *rv = lfirst(cell);
1671  Relation rel;
1672  bool recurse = rv->inh;
1673  Oid myrelid;
1674  LOCKMODE lockmode = AccessExclusiveLock;
1675 
1676  myrelid = RangeVarGetRelidExtended(rv, lockmode,
1678  NULL);
1679 
1680  /* don't throw error for "TRUNCATE foo, foo" */
1681  if (list_member_oid(relids, myrelid))
1682  continue;
1683 
1684  /* open the relation, we already hold a lock on it */
1685  rel = table_open(myrelid, NoLock);
1686 
1687  /*
1688  * RangeVarGetRelidExtended() has done most checks with its callback,
1689  * but other checks with the now-opened Relation remain.
1690  */
1692 
1693  rels = lappend(rels, rel);
1694  relids = lappend_oid(relids, myrelid);
1695 
1696  /* Log this relation only if needed for logical decoding */
1697  if (RelationIsLogicallyLogged(rel))
1698  relids_logged = lappend_oid(relids_logged, myrelid);
1699 
1700  if (recurse)
1701  {
1702  ListCell *child;
1703  List *children;
1704 
1705  children = find_all_inheritors(myrelid, lockmode, NULL);
1706 
1707  foreach(child, children)
1708  {
1709  Oid childrelid = lfirst_oid(child);
1710 
1711  if (list_member_oid(relids, childrelid))
1712  continue;
1713 
1714  /* find_all_inheritors already got lock */
1715  rel = table_open(childrelid, NoLock);
1716 
1717  /*
1718  * It is possible that the parent table has children that are
1719  * temp tables of other backends. We cannot safely access
1720  * such tables (because of buffering issues), and the best
1721  * thing to do is to silently ignore them. Note that this
1722  * check is the same as one of the checks done in
1723  * truncate_check_activity() called below, still it is kept
1724  * here for simplicity.
1725  */
1726  if (RELATION_IS_OTHER_TEMP(rel))
1727  {
1728  table_close(rel, lockmode);
1729  continue;
1730  }
1731 
1732  /*
1733  * Inherited TRUNCATE commands perform access permission
1734  * checks on the parent table only. So we skip checking the
1735  * children's permissions and don't call
1736  * truncate_check_perms() here.
1737  */
1740 
1741  rels = lappend(rels, rel);
1742  relids = lappend_oid(relids, childrelid);
1743 
1744  /* Log this relation only if needed for logical decoding */
1745  if (RelationIsLogicallyLogged(rel))
1746  relids_logged = lappend_oid(relids_logged, childrelid);
1747  }
1748  }
1749  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1750  ereport(ERROR,
1751  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1752  errmsg("cannot truncate only a partitioned table"),
1753  errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
1754  }
1755 
1756  ExecuteTruncateGuts(rels, relids, relids_logged,
1757  stmt->behavior, stmt->restart_seqs);
1758 
1759  /* And close the rels */
1760  foreach(cell, rels)
1761  {
1762  Relation rel = (Relation) lfirst(cell);
1763 
1764  table_close(rel, NoLock);
1765  }
1766 }
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:256
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:685
struct RelationData * Relation
Definition: relcache.h:26
List * relations
Definition: parsenodes.h:3130
DropBehavior behavior
Definition: parsenodes.h:3132
bool restart_seqs
Definition: parsenodes.h:3131
static void truncate_check_activity(Relation rel)
Definition: tablecmds.c:2215
static void truncate_check_rel(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2157
void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs)
Definition: tablecmds.c:1782
static void RangeVarCallbackForTruncate(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
Definition: tablecmds.c:16955

References AccessExclusiveLock, TruncateStmt::behavior, ereport, errcode(), errhint(), errmsg(), ERROR, ExecuteTruncateGuts(), find_all_inheritors(), RangeVar::inh, lappend(), lappend_oid(), lfirst, lfirst_oid, list_member_oid(), NIL, NoLock, RangeVarCallbackForTruncate(), RangeVarGetRelidExtended(), RelationData::rd_rel, RELATION_IS_OTHER_TEMP, RelationGetRelid, RelationIsLogicallyLogged, TruncateStmt::relations, TruncateStmt::restart_seqs, table_close(), table_open(), truncate_check_activity(), and truncate_check_rel().

Referenced by standard_ProcessUtility().

◆ ExecuteTruncateGuts()

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

Definition at line 1782 of file tablecmds.c.

1786 {
1787  List *rels;
1788  List *seq_relids = NIL;
1789  HTAB *ft_htab = NULL;
1790  EState *estate;
1791  ResultRelInfo *resultRelInfos;
1792  ResultRelInfo *resultRelInfo;
1793  SubTransactionId mySubid;
1794  ListCell *cell;
1795  Oid *logrelids;
1796 
1797  /*
1798  * Check the explicitly-specified relations.
1799  *
1800  * In CASCADE mode, suck in all referencing relations as well. This
1801  * requires multiple iterations to find indirectly-dependent relations. At
1802  * each phase, we need to exclusive-lock new rels before looking for their
1803  * dependencies, else we might miss something. Also, we check each rel as
1804  * soon as we open it, to avoid a faux pas such as holding lock for a long
1805  * time on a rel we have no permissions for.
1806  */
1807  rels = list_copy(explicit_rels);
1808  if (behavior == DROP_CASCADE)
1809  {
1810  for (;;)
1811  {
1812  List *newrelids;
1813 
1814  newrelids = heap_truncate_find_FKs(relids);
1815  if (newrelids == NIL)
1816  break; /* nothing else to add */
1817 
1818  foreach(cell, newrelids)
1819  {
1820  Oid relid = lfirst_oid(cell);
1821  Relation rel;
1822 
1823  rel = table_open(relid, AccessExclusiveLock);
1824  ereport(NOTICE,
1825  (errmsg("truncate cascades to table \"%s\"",
1826  RelationGetRelationName(rel))));
1827  truncate_check_rel(relid, rel->rd_rel);
1828  truncate_check_perms(relid, rel->rd_rel);
1830  rels = lappend(rels, rel);
1831  relids = lappend_oid(relids, relid);
1832 
1833  /* Log this relation only if needed for logical decoding */
1834  if (RelationIsLogicallyLogged(rel))
1835  relids_logged = lappend_oid(relids_logged, relid);
1836  }
1837  }
1838  }
1839 
1840  /*
1841  * Check foreign key references. In CASCADE mode, this should be
1842  * unnecessary since we just pulled in all the references; but as a
1843  * cross-check, do it anyway if in an Assert-enabled build.
1844  */
1845 #ifdef USE_ASSERT_CHECKING
1846  heap_truncate_check_FKs(rels, false);
1847 #else
1848  if (behavior == DROP_RESTRICT)
1849  heap_truncate_check_FKs(rels, false);
1850 #endif
1851 
1852  /*
1853  * If we are asked to restart sequences, find all the sequences, lock them
1854  * (we need AccessExclusiveLock for ResetSequence), and check permissions.
1855  * We want to do this early since it's pointless to do all the truncation
1856  * work only to fail on sequence permissions.
1857  */
1858  if (restart_seqs)
1859  {
1860  foreach(cell, rels)
1861  {
1862  Relation rel = (Relation) lfirst(cell);
1863  List *seqlist = getOwnedSequences(RelationGetRelid(rel));
1864  ListCell *seqcell;
1865 
1866  foreach(seqcell, seqlist)
1867  {
1868  Oid seq_relid = lfirst_oid(seqcell);
1869  Relation seq_rel;
1870 
1871  seq_rel = relation_open(seq_relid, AccessExclusiveLock);
1872 
1873  /* This check must match AlterSequence! */
1874  if (!pg_class_ownercheck(seq_relid, GetUserId()))
1876  RelationGetRelationName(seq_rel));
1877 
1878  seq_relids = lappend_oid(seq_relids, seq_relid);
1879 
1880  relation_close(seq_rel, NoLock);
1881  }
1882  }
1883  }
1884 
1885  /* Prepare to catch AFTER triggers. */
1887 
1888  /*
1889  * To fire triggers, we'll need an EState as well as a ResultRelInfo for
1890  * each relation. We don't need to call ExecOpenIndices, though.
1891  *
1892  * We put the ResultRelInfos in the es_opened_result_relations list, even
1893  * though we don't have a range table and don't populate the
1894  * es_result_relations array. That's a bit bogus, but it's enough to make
1895  * ExecGetTriggerResultRel() find them.
1896  */
1897  estate = CreateExecutorState();
1898  resultRelInfos = (ResultRelInfo *)
1899  palloc(list_length(rels) * sizeof(ResultRelInfo));
1900  resultRelInfo = resultRelInfos;
1901  foreach(cell, rels)
1902  {
1903  Relation rel = (Relation) lfirst(cell);
1904 
1905  InitResultRelInfo(resultRelInfo,
1906  rel,
1907  0, /* dummy rangetable index */
1908  NULL,
1909  0);
1910  estate->es_opened_result_relations =
1911  lappend(estate->es_opened_result_relations, resultRelInfo);
1912  resultRelInfo++;
1913  }
1914 
1915  /*
1916  * Process all BEFORE STATEMENT TRUNCATE triggers before we begin
1917  * truncating (this is because one of them might throw an error). Also, if
1918  * we were to allow them to prevent statement execution, that would need
1919  * to be handled here.
1920  */
1921  resultRelInfo = resultRelInfos;
1922  foreach(cell, rels)
1923  {
1924  ExecBSTruncateTriggers(estate, resultRelInfo);
1925  resultRelInfo++;
1926  }
1927 
1928  /*
1929  * OK, truncate each table.
1930  */
1931  mySubid = GetCurrentSubTransactionId();
1932 
1933  foreach(cell, rels)
1934  {
1935  Relation rel = (Relation) lfirst(cell);
1936 
1937  /* Skip partitioned tables as there is nothing to do */
1938  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1939  continue;
1940 
1941  /*
1942  * Build the lists of foreign tables belonging to each foreign server
1943  * and pass each list to the foreign data wrapper's callback function,
1944  * so that each server can truncate its all foreign tables in bulk.
1945  * Each list is saved as a single entry in a hash table that uses the
1946  * server OID as lookup key.
1947  */
1948  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1949  {
1951  bool found;
1952  ForeignTruncateInfo *ft_info;
1953 
1954  /* First time through, initialize hashtable for foreign tables */
1955  if (!ft_htab)
1956  {
1957  HASHCTL hctl;
1958 
1959  memset(&hctl, 0, sizeof(HASHCTL));
1960  hctl.keysize = sizeof(Oid);
1961  hctl.entrysize = sizeof(ForeignTruncateInfo);
1962  hctl.hcxt = CurrentMemoryContext;
1963 
1964  ft_htab = hash_create("TRUNCATE for Foreign Tables",
1965  32, /* start small and extend */
1966  &hctl,
1968  }
1969 
1970  /* Find or create cached entry for the foreign table */
1971  ft_info = hash_search(ft_htab, &serverid, HASH_ENTER, &found);
1972  if (!found)
1973  {
1974  ft_info->serverid = serverid;
1975  ft_info->rels = NIL;
1976  }
1977 
1978  /*
1979  * Save the foreign table in the entry of the server that the
1980  * foreign table belongs to.
1981  */
1982  ft_info->rels = lappend(ft_info->rels, rel);
1983  continue;
1984  }
1985 
1986  /*
1987  * Normally, we need a transaction-safe truncation here. However, if
1988  * the table was either created in the current (sub)transaction or has
1989  * a new relfilenode in the current (sub)transaction, then we can just
1990  * truncate it in-place, because a rollback would cause the whole
1991  * table or the current physical file to be thrown away anyway.
1992  */
1993  if (rel->rd_createSubid == mySubid ||
1994  rel->rd_newRelfilenodeSubid == mySubid)
1995  {
1996  /* Immediate, non-rollbackable truncation is OK */
1997  heap_truncate_one_rel(rel);
1998  }
1999  else
2000  {
2001  Oid heap_relid;
2002  Oid toast_relid;
2003  ReindexParams reindex_params = {0};
2004 
2005  /*
2006  * This effectively deletes all rows in the table, and may be done
2007  * in a serializable transaction. In that case we must record a
2008  * rw-conflict in to this transaction from each transaction
2009  * holding a predicate lock on the table.
2010  */
2012 
2013  /*
2014  * Need the full transaction-safe pushups.
2015  *
2016  * Create a new empty storage file for the relation, and assign it
2017  * as the relfilenode value. The old storage file is scheduled for
2018  * deletion at commit.
2019  */
2020  RelationSetNewRelfilenode(rel, rel->rd_rel->relpersistence);
2021 
2022  heap_relid = RelationGetRelid(rel);
2023 
2024  /*
2025  * The same for the toast table, if any.
2026  */
2027  toast_relid = rel->rd_rel->reltoastrelid;
2028  if (OidIsValid(toast_relid))
2029  {
2030  Relation toastrel = relation_open(toast_relid,
2032 
2033  RelationSetNewRelfilenode(toastrel,
2034  toastrel->rd_rel->relpersistence);
2035  table_close(toastrel, NoLock);
2036  }
2037 
2038  /*
2039  * Reconstruct the indexes to match, and we're done.
2040  */
2042  &reindex_params);
2043  }
2044 
2045  pgstat_count_truncate(rel);
2046  }
2047 
2048  /* Now go through the hash table, and truncate foreign tables */
2049  if (ft_htab)
2050  {
2051  ForeignTruncateInfo *ft_info;
2052  HASH_SEQ_STATUS seq;
2053 
2054  hash_seq_init(&seq, ft_htab);
2055 
2056  PG_TRY();
2057  {
2058  while ((ft_info = hash_seq_search(&seq)) != NULL)
2059  {
2060  FdwRoutine *routine = GetFdwRoutineByServerId(ft_info->serverid);
2061 
2062  /* truncate_check_rel() has checked that already */
2063  Assert(routine->ExecForeignTruncate != NULL);
2064 
2065  routine->ExecForeignTruncate(ft_info->rels,
2066  behavior,
2067  restart_seqs);
2068  }
2069  }
2070  PG_FINALLY();
2071  {
2072  hash_destroy(ft_htab);
2073  }
2074  PG_END_TRY();
2075  }
2076 
2077  /*
2078  * Restart owned sequences if we were asked to.
2079  */
2080  foreach(cell, seq_relids)
2081  {
2082  Oid seq_relid = lfirst_oid(cell);
2083 
2084  ResetSequence(seq_relid);
2085  }
2086 
2087  /*
2088  * Write a WAL record to allow this set of actions to be logically
2089  * decoded.
2090  *
2091  * Assemble an array of relids so we can write a single WAL record for the
2092  * whole action.
2093  */
2094  if (list_length(relids_logged) > 0)
2095  {
2096  xl_heap_truncate xlrec;
2097  int i = 0;
2098 
2099  /* should only get here if wal_level >= logical */
2101 
2102  logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
2103  foreach(cell, relids_logged)
2104  logrelids[i++] = lfirst_oid(cell);
2105 
2106  xlrec.dbId = MyDatabaseId;
2107  xlrec.nrelids = list_length(relids_logged);
2108  xlrec.flags = 0;
2109  if (behavior == DROP_CASCADE)
2110  xlrec.flags |= XLH_TRUNCATE_CASCADE;
2111  if (restart_seqs)
2113 
2114  XLogBeginInsert();
2115  XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
2116  XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
2117 
2119 
2120  (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
2121  }
2122 
2123  /*
2124  * Process all AFTER STATEMENT TRUNCATE triggers.
2125  */
2126  resultRelInfo = resultRelInfos;
2127  foreach(cell, rels)
2128  {
2129  ExecASTruncateTriggers(estate, resultRelInfo);
2130  resultRelInfo++;
2131  }
2132 
2133  /* Handle queued AFTER triggers */
2134  AfterTriggerEndQuery(estate);
2135 
2136  /* We can clean up the EState now */
2137  FreeExecutorState(estate);
2138 
2139  /*
2140  * Close any rels opened by CASCADE (can't do this while EState still
2141  * holds refs)
2142  */
2143  rels = list_difference_ptr(rels, explicit_rels);
2144  foreach(cell, rels)
2145  {
2146  Relation rel = (Relation) lfirst(cell);
2147 
2148  table_close(rel, NoLock);
2149  }
2150 }
uint32 SubTransactionId
Definition: c.h:602
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:862
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
#define PG_END_TRY()
Definition: elog.h:324
#define PG_TRY()
Definition: elog.h:299
#define PG_FINALLY()
Definition: elog.h:316
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition: execMain.c:1195
EState * CreateExecutorState(void)
Definition: execUtils.c:90
void FreeExecutorState(EState *estate)
Definition: execUtils.c:186
struct ResultRelInfo ResultRelInfo
Oid GetForeignServerIdByRelId(Oid relid)
Definition: foreign.c:341
FdwRoutine * GetFdwRoutineByServerId(Oid serverid)
Definition: foreign.c:363
Oid MyDatabaseId
Definition: globals.c:89
List * heap_truncate_find_FKs(List *relationIds)
Definition: heap.c:3181
void heap_truncate_check_FKs(List *relations, bool tempTables)
Definition: heap.c:3086
void heap_truncate_one_rel(Relation rel)
Definition: heap.c:3042
#define XLOG_HEAP_TRUNCATE
Definition: heapam_xlog.h:35
#define XLH_TRUNCATE_RESTART_SEQS
Definition: heapam_xlog.h:121
#define SizeOfHeapTruncate
Definition: heapam_xlog.h:136
#define XLH_TRUNCATE_CASCADE
Definition: heapam_xlog.h:120
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
bool reindex_relation(Oid relid, int flags, ReindexParams *params)
Definition: index.c:3859
#define REINDEX_REL_PROCESS_TOAST
Definition: index.h:155
List * list_difference_ptr(const List *list1, const List *list2)
Definition: list.c:1262
List * list_copy(const List *oldlist)
Definition: list.c:1572
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
@ DROP_CASCADE
Definition: parsenodes.h:2209
@ DROP_RESTRICT
Definition: parsenodes.h:2208
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2172
List * getOwnedSequences(Oid relid)
Definition: pg_depend.c:878
void pgstat_count_truncate(Relation rel)
void CheckTableForSerializableConflictIn(Relation relation)
Definition: predicate.c:4531
void RelationSetNewRelfilenode(Relation relation, char persistence)
Definition: relcache.c:3700
void ResetSequence(Oid seq_relid)
Definition: sequence.c:266
List * es_opened_result_relations
Definition: execnodes.h:610
ExecForeignTruncate_function ExecForeignTruncate
Definition: fdwapi.h:263
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
MemoryContext hcxt
Definition: hsearch.h:86
Definition: dynahash.c:220
SubTransactionId rd_newRelfilenodeSubid
Definition: rel.h:103
SubTransactionId rd_createSubid
Definition: rel.h:102
struct ForeignTruncateInfo ForeignTruncateInfo
static void truncate_check_perms(Oid relid, Form_pg_class reltuple)
Definition: tablecmds.c:2197
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3213
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
Definition: trigger.c:3260
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:4981
void AfterTriggerBeginQuery(void)
Definition: trigger.c:4961
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:776
#define XLogLogicalInfoActive()
Definition: xlog.h:121
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:149
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:443
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:425
void XLogBeginInsert(void)
Definition: xloginsert.c:150
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:351

References AccessExclusiveLock, aclcheck_error(), ACLCHECK_NOT_OWNER, AfterTriggerBeginQuery(), AfterTriggerEndQuery(), Assert(), CheckTableForSerializableConflictIn(), CreateExecutorState(), CurrentMemoryContext, xl_heap_truncate::dbId, DROP_CASCADE, DROP_RESTRICT, HASHCTL::entrysize, ereport, errmsg(), EState::es_opened_result_relations, ExecASTruncateTriggers(), ExecBSTruncateTriggers(), FdwRoutine::ExecForeignTruncate, xl_heap_truncate::flags, FreeExecutorState(), GetCurrentSubTransactionId(), GetFdwRoutineByServerId(), GetForeignServerIdByRelId(), getOwnedSequences(), GetUserId(), HASH_BLOBS, HASH_CONTEXT, hash_create(), hash_destroy(), HASH_ELEM, HASH_ENTER, hash_search(), hash_seq_init(), hash_seq_search(), HASHCTL::hcxt, heap_truncate_check_FKs(), heap_truncate_find_FKs(), heap_truncate_one_rel(), i, InitResultRelInfo(), HASHCTL::keysize, lappend(), lappend_oid(), lfirst, lfirst_oid, list_copy(), list_difference_ptr(), list_length(), MyDatabaseId, NIL, NoLock, NOTICE, xl_heap_truncate::nrelids, OBJECT_SEQUENCE, OidIsValid, palloc(), pg_class_ownercheck(), PG_END_TRY, PG_FINALLY, PG_TRY, pgstat_count_truncate(), RelationData::rd_createSubid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_rel, REINDEX_REL_PROCESS_TOAST, reindex_relation(), relation_close(), relation_open(), RelationGetRelationName, RelationGetRelid, RelationIsLogicallyLogged, RelationSetNewRelfilenode(), ForeignTruncateInfo::rels, ResetSequence(), ForeignTruncateInfo::serverid, SizeOfHeapTruncate, table_close(), table_open(), truncate_check_activity(), truncate_check_perms(), truncate_check_rel(), XLH_TRUNCATE_CASCADE, XLH_TRUNCATE_RESTART_SEQS, XLOG_HEAP_TRUNCATE, XLOG_INCLUDE_ORIGIN, XLogBeginInsert(), XLogInsert(), XLogLogicalInfoActive, XLogRegisterData(), and XLogSetRecordFlags().

Referenced by apply_handle_truncate(), and ExecuteTruncate().

◆ find_composite_type_dependencies()

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

Definition at line 6414 of file tablecmds.c.

6416 {
6417  Relation depRel;
6418  ScanKeyData key[2];
6419  SysScanDesc depScan;
6420  HeapTuple depTup;
6421 
6422  /* since this function recurses, it could be driven to stack overflow */
6424 
6425  /*
6426  * We scan pg_depend to find those things that depend on the given type.
6427  * (We assume we can ignore refobjsubid for a type.)
6428  */
6429  depRel = table_open(DependRelationId, AccessShareLock);
6430 
6431  ScanKeyInit(&key[0],
6432  Anum_pg_depend_refclassid,
6433  BTEqualStrategyNumber, F_OIDEQ,
6434  ObjectIdGetDatum(TypeRelationId));
6435  ScanKeyInit(&key[1],
6436  Anum_pg_depend_refobjid,
6437  BTEqualStrategyNumber, F_OIDEQ,
6438  ObjectIdGetDatum(typeOid));
6439 
6440  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
6441  NULL, 2, key);
6442 
6443  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
6444  {
6445  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
6446  Relation rel;
6447  Form_pg_attribute att;
6448 
6449  /* Check for directly dependent types */
6450  if (pg_depend->classid == TypeRelationId)
6451  {
6452  /*
6453  * This must be an array, domain, or range containing the given
6454  * type, so recursively check for uses of this type. Note that
6455  * any error message will mention the original type not the
6456  * container; this is intentional.
6457  */
6458  find_composite_type_dependencies(pg_depend->objid,
6459  origRelation, origTypeName);
6460  continue;
6461  }
6462 
6463  /* Else, ignore dependees that aren't user columns of relations */
6464  /* (we assume system columns are never of interesting types) */
6465  if (pg_depend->classid != RelationRelationId ||
6466  pg_depend->objsubid <= 0)
6467  continue;
6468 
6469  rel = relation_open(pg_depend->objid, AccessShareLock);
6470  att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
6471 
6472  if (rel->rd_rel->relkind == RELKIND_RELATION ||
6473  rel->rd_rel->relkind == RELKIND_MATVIEW ||
6474  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6475  {
6476  if (origTypeName)
6477  ereport(ERROR,
6478  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6479  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6480  origTypeName,
6482  NameStr(att->attname))));
6483  else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
6484  ereport(ERROR,
6485  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6486  errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
6487  RelationGetRelationName(origRelation),
6489  NameStr(att->attname))));
6490  else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
6491  ereport(ERROR,
6492  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6493  errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
6494  RelationGetRelationName(origRelation),
6496  NameStr(att->attname))));
6497  else
6498  ereport(ERROR,
6499  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6500  errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
6501  RelationGetRelationName(origRelation),
6503  NameStr(att->attname))));
6504  }
6505  else if (OidIsValid(rel->rd_rel->reltype))
6506  {
6507  /*
6508  * A view or composite type itself isn't a problem, but we must
6509  * recursively check for indirect dependencies via its rowtype.
6510  */
6512  origRelation, origTypeName);
6513  }
6514 
6516  }
6517 
6518  systable_endscan(depScan);
6519 
6521 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:598
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:505
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:386
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
void check_stack_depth(void)
Definition: postgres.c:3500
TupleDesc rd_att
Definition: rel.h:110
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:6414

References AccessShareLock, BTEqualStrategyNumber, check_stack_depth(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, sort-test::key, NameStr, ObjectIdGetDatum, OidIsValid, RelationData::rd_att, RelationData::rd_rel, relation_close(), relation_open(), RelationGetRelationName, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_open(), and TupleDescAttr.

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

◆ PartConstraintImpliedByRelConstraint()

bool PartConstraintImpliedByRelConstraint ( Relation  scanrel,
List partConstraint 
)

Definition at line 17475 of file tablecmds.c.

17477 {
17478  List *existConstraint = NIL;
17479  TupleConstr *constr = RelationGetDescr(scanrel)->constr;
17480  int i;
17481 
17482  if (constr && constr->has_not_null)
17483  {
17484  int natts = scanrel->rd_att->natts;
17485 
17486  for (i = 1; i <= natts; i++)
17487  {
17488  Form_pg_attribute att = TupleDescAttr(scanrel->rd_att, i - 1);
17489 
17490  if (att->attnotnull && !att->attisdropped)
17491  {
17492  NullTest *ntest = makeNode(NullTest);
17493 
17494  ntest->arg = (Expr *) makeVar(1,
17495  i,
17496  att->atttypid,
17497  att->atttypmod,
17498  att->attcollation,
17499  0);
17500  ntest->nulltesttype = IS_NOT_NULL;
17501 
17502  /*
17503  * argisrow=false is correct even for a composite column,
17504  * because attnotnull does not represent a SQL-spec IS NOT
17505  * NULL test in such a case, just IS DISTINCT FROM NULL.
17506  */
17507  ntest->argisrow = false;
17508  ntest->location = -1;
17509  existConstraint = lappend(existConstraint, ntest);
17510  }
17511  }
17512  }
17513 
17514  return ConstraintImpliedByRelConstraint(scanrel, partConstraint, existConstraint);
17515 }
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
@ IS_NOT_NULL
Definition: primnodes.h:1632
NullTestType nulltesttype
Definition: primnodes.h:1639
int location
Definition: primnodes.h:1641
bool argisrow
Definition: primnodes.h:1640
Expr * arg
Definition: primnodes.h:1638
bool has_not_null
Definition: tupdesc.h:44
static bool ConstraintImpliedByRelConstraint(Relation scanrel, List *testConstraint, List *provenConstraint)
Definition: tablecmds.c:17528

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

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

◆ PreCommit_on_commit_actions()

void PreCommit_on_commit_actions ( void  )

Definition at line 16756 of file tablecmds.c.

16757 {
16758  ListCell *l;
16759  List *oids_to_truncate = NIL;
16760  List *oids_to_drop = NIL;
16761 
16762  foreach(l, on_commits)
16763  {
16764  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
16765 
16766  /* Ignore entry if already dropped in this xact */
16768  continue;
16769 
16770  switch (oc->oncommit)
16771  {
16772  case ONCOMMIT_NOOP:
16774  /* Do nothing (there shouldn't be such entries, actually) */
16775  break;
16776  case ONCOMMIT_DELETE_ROWS:
16777 
16778  /*
16779  * If this transaction hasn't accessed any temporary
16780  * relations, we can skip truncating ON COMMIT DELETE ROWS
16781  * tables, as they must still be empty.
16782  */
16784  oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
16785  break;
16786  case ONCOMMIT_DROP:
16787  oids_to_drop = lappend_oid(oids_to_drop, oc->relid);
16788  break;
16789  }
16790  }
16791 
16792  /*
16793  * Truncate relations before dropping so that all dependencies between
16794  * relations are removed after they are worked on. Doing it like this
16795  * might be a waste as it is possible that a relation being truncated will
16796  * be dropped anyway due to its parent being dropped, but this makes the
16797  * code more robust because of not having to re-check that the relation
16798  * exists at truncation time.
16799  */
16800  if (oids_to_truncate != NIL)
16801  heap_truncate(oids_to_truncate);
16802 
16803  if (oids_to_drop != NIL)
16804  {
16805  ObjectAddresses *targetObjects = new_object_addresses();
16806  ListCell *l;
16807 
16808  foreach(l, oids_to_drop)
16809  {
16810  ObjectAddress object;
16811 
16812  object.classId = RelationRelationId;
16813  object.objectId = lfirst_oid(l);
16814  object.objectSubId = 0;
16815 
16816  Assert(!object_address_present(&object, targetObjects));
16817 
16818  add_exact_object_address(&object, targetObjects);
16819  }
16820 
16821  /*
16822  * Since this is an automatic drop, rather than one directly initiated
16823  * by the user, we pass the PERFORM_DELETION_INTERNAL flag.
16824  */
16825  performMultipleDeletions(targetObjects, DROP_CASCADE,
16827 
16828 #ifdef USE_ASSERT_CHECKING
16829 
16830  /*
16831  * Note that table deletion will call remove_on_commit_action, so the
16832  * entry should get marked as deleted.
16833  */
16834  foreach(l, on_commits)
16835  {
16836  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
16837 
16838  if (oc->oncommit != ONCOMMIT_DROP)
16839  continue;
16840 
16842  }
16843 #endif
16844  }
16845 }
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:376
#define PERFORM_DELETION_QUIETLY
Definition: dependency.h:137
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:135
void heap_truncate(List *relids)
Definition: heap.c:3001
@ ONCOMMIT_DELETE_ROWS
Definition: primnodes.h:51
@ ONCOMMIT_PRESERVE_ROWS
Definition: primnodes.h:50
@ ONCOMMIT_DROP
Definition: primnodes.h:52
OnCommitAction oncommit
Definition: tablecmds.c:112
int MyXactFlags
Definition: xact.c:135
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:102

References add_exact_object_address(), Assert(), ObjectAddress::classId, OnCommitItem::deleting_subid, DROP_CASCADE, heap_truncate(), InvalidSubTransactionId, lappend_oid(), lfirst, lfirst_oid, MyXactFlags, new_object_addresses(), NIL, object_address_present(), on_commits, OnCommitItem::oncommit, ONCOMMIT_DELETE_ROWS, ONCOMMIT_DROP, ONCOMMIT_NOOP, ONCOMMIT_PRESERVE_ROWS, PERFORM_DELETION_INTERNAL, PERFORM_DELETION_QUIETLY, performMultipleDeletions(), OnCommitItem::relid, and XACT_FLAGS_ACCESSEDTEMPNAMESPACE.

Referenced by CommitTransaction(), and PrepareTransaction().

◆ RangeVarCallbackOwnsRelation()

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

Definition at line 16979 of file tablecmds.c.

16981 {
16982  HeapTuple tuple;
16983 
16984  /* Nothing to do if the relation was not found. */
16985  if (!OidIsValid(relId))
16986  return;
16987 
16988  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId));
16989  if (!HeapTupleIsValid(tuple)) /* should not happen */
16990  elog(ERROR, "cache lookup failed for relation %u", relId);
16991 
16992  if (!pg_class_ownercheck(relId, GetUserId()))
16994  relation->relname);
16995 
16996  if (!allowSystemTableMods &&
16997  IsSystemClass(relId, (Form_pg_class) GETSTRUCT(tuple)))
16998  ereport(ERROR,
16999  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
17000  errmsg("permission denied: \"%s\" is a system catalog",
17001  relation->relname)));
17002 
17003  ReleaseSysCache(tuple);
17004 }
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:87

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

◆ RangeVarCallbackOwnsTable()

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

Definition at line 16923 of file tablecmds.c.

16925 {
16926  char relkind;
16927 
16928  /* Nothing to do if the relation was not found. */
16929  if (!OidIsValid(relId))
16930  return;
16931 
16932  /*
16933  * If the relation does exist, check whether it's an index. But note that
16934  * the relation might have been dropped between the time we did the name
16935  * lookup and now. In that case, there's nothing to do.
16936  */
16937  relkind = get_rel_relkind(relId);
16938  if (!relkind)
16939  return;
16940  if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
16941  relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
16942  ereport(ERROR,
16943  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16944  errmsg("\"%s\" is not a table or materialized view", relation->relname)));
16945 
16946  /* Check permissions */
16947  if (!pg_class_ownercheck(relId, GetUserId()))
16949 }

References aclcheck_error(), ACLCHECK_NOT_OWNER, ereport, errcode(), errmsg(), ERROR, get_rel_relkind(), get_relkind_objtype(), GetUserId(), OidIsValid, pg_class_ownercheck(), and RangeVar::relname.

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

◆ register_on_commit_action()

void register_on_commit_action ( Oid  relid,
OnCommitAction  action 
)

Definition at line 16697 of file tablecmds.c.

16698 {
16699  OnCommitItem *oc;
16700  MemoryContext oldcxt;
16701 
16702  /*
16703  * We needn't bother registering the relation unless there is an ON COMMIT
16704  * action we need to take.
16705  */
16707  return;
16708 
16710 
16711  oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
16712  oc->relid = relid;
16713  oc->oncommit = action;
16716 
16717  /*
16718  * We use lcons() here so that ON COMMIT actions are processed in reverse
16719  * order of registration. That might not be essential but it seems
16720  * reasonable.
16721  */
16722  on_commits = lcons(oc, on_commits);
16723 
16724  MemoryContextSwitchTo(oldcxt);
16725 }
List * lcons(void *datum, List *list)
Definition: list.c:494
MemoryContext CacheMemoryContext
Definition: mcxt.c:51
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109

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

Referenced by heap_create_with_catalog().

◆ remove_on_commit_action()

void remove_on_commit_action ( Oid  relid)

Definition at line 16733 of file tablecmds.c.

16734 {
16735  ListCell *l;
16736 
16737  foreach(l, on_commits)
16738  {
16739  OnCommitItem *oc = (OnCommitItem *) lfirst(l);
16740 
16741  if (oc->relid == relid)
16742  {
16744  break;
16745  }
16746  }
16747 }

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

Referenced by heap_drop_with_catalog().

◆ RemoveRelations()

void RemoveRelations ( DropStmt drop)

Definition at line 1335 of file tablecmds.c.

1336 {
1337  ObjectAddresses *objects;
1338  char relkind;
1339  ListCell *cell;
1340  int flags = 0;
1341  LOCKMODE lockmode = AccessExclusiveLock;
1342 
1343  /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
1344  if (drop->concurrent)
1345  {
1346  /*
1347  * Note that for temporary relations this lock may get upgraded later
1348  * on, but as no other session can access a temporary relation, this
1349  * is actually fine.
1350  */
1351  lockmode = ShareUpdateExclusiveLock;
1352  Assert(drop->removeType == OBJECT_INDEX);
1353  if (list_length(drop->objects) != 1)
1354  ereport(ERROR,
1355  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1356  errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
1357  if (drop->behavior == DROP_CASCADE)
1358  ereport(ERROR,
1359  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1360  errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
1361  }
1362 
1363  /*
1364  * First we identify all the relations, then we delete them in a single
1365  * performMultipleDeletions() call. This is to avoid unwanted DROP
1366  * RESTRICT errors if one of the relations depends on another.
1367  */
1368 
1369  /* Determine required relkind */
1370  switch (drop->removeType)
1371  {
1372  case OBJECT_TABLE:
1373  relkind = RELKIND_RELATION;
1374  break;
1375 
1376  case OBJECT_INDEX:
1377  relkind = RELKIND_INDEX;
1378  break;
1379 
1380  case OBJECT_SEQUENCE:
1381  relkind = RELKIND_SEQUENCE;
1382  break;
1383 
1384  case OBJECT_VIEW:
1385  relkind = RELKIND_VIEW;
1386  break;
1387 
1388  case OBJECT_MATVIEW:
1389  relkind = RELKIND_MATVIEW;
1390  break;
1391 
1392  case OBJECT_FOREIGN_TABLE:
1393  relkind = RELKIND_FOREIGN_TABLE;
1394  break;
1395 
1396  default:
1397  elog(ERROR, "unrecognized drop object type: %d",
1398  (int) drop->removeType);
1399  relkind = 0; /* keep compiler quiet */
1400  break;
1401  }
1402 
1403  /* Lock and validate each relation; build a list of object addresses */
1404  objects = new_object_addresses();
1405 
1406  foreach(cell, drop->objects)
1407  {
1408  RangeVar *rel = makeRangeVarFromNameList((List *) lfirst(cell));
1409  Oid relOid;
1410  ObjectAddress obj;
1412 
1413  /*
1414  * These next few steps are a great deal like relation_openrv, but we
1415  * don't bother building a relcache entry since we don't need it.
1416  *
1417  * Check for shared-cache-inval messages before trying to access the
1418  * relation. This is needed to cover the case where the name
1419  * identifies a rel that has been dropped and recreated since the
1420  * start of our transaction: if we don't flush the old syscache entry,
1421  * then we'll latch onto that entry and suffer an error later.
1422  */
1424 
1425  /* Look up the appropriate relation using namespace search. */
1426  state.expected_relkind = relkind;
1427  state.heap_lockmode = drop->concurrent ?
1429  /* We must initialize these fields to show that no locks are held: */
1430  state.heapOid = InvalidOid;
1431  state.partParentOid = InvalidOid;
1432 
1433  relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK,
1435  (void *) &state);
1436 
1437  /* Not there? */
1438  if (!OidIsValid(relOid))
1439  {
1440  DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
1441  continue;
1442  }
1443 
1444  /*
1445  * Decide if concurrent mode needs to be used here or not. The
1446  * callback retrieved the rel's persistence for us.
1447  */
1448  if (drop->concurrent &&
1449  state.actual_relpersistence != RELPERSISTENCE_TEMP)
1450  {
1451  Assert(list_length(drop->objects) == 1 &&
1452  drop->removeType == OBJECT_INDEX);
1454  }
1455 
1456  /*
1457  * Concurrent index drop cannot be used with partitioned indexes,
1458  * either.
1459  */
1460  if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 &&
1461  state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1462  ereport(ERROR,
1463  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1464  errmsg("cannot drop partitioned index \"%s\" concurrently",
1465  rel->relname)));
1466 
1467  /*
1468  * If we're told to drop a partitioned index, we must acquire lock on
1469  * all the children of its parent partitioned table before proceeding.
1470  * Otherwise we'd try to lock the child index partitions before their
1471  * tables, leading to potential deadlock against other sessions that
1472  * will lock those objects in the other order.
1473  */
1474  if (state.actual_relkind == RELKIND_PARTITIONED_INDEX)
1475  (void) find_all_inheritors(state.heapOid,
1476  state.heap_lockmode,
1477  NULL);
1478 
1479  /* OK, we're ready to delete this one */
1480  obj.classId = RelationRelationId;
1481  obj.objectId = relOid;
1482  obj.objectSubId = 0;
1483 
1484  add_exact_object_address(&obj, objects);
1485  }
1486 
1487  performMultipleDeletions(objects, drop->behavior, flags);
1488 
1489  free_object_addresses(objects);
1490 }
#define PERFORM_DELETION_CONCURRENTLY
Definition: dependency.h:136
void AcceptInvalidationMessages(void)
Definition: inval.c:746
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3108
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2153
@ OBJECT_VIEW
Definition: parsenodes.h:2186
bool missing_ok
Definition: parsenodes.h:3119
List * objects
Definition: parsenodes.h:3116
ObjectType removeType
Definition: parsenodes.h:3117
bool concurrent
Definition: parsenodes.h:3120
DropBehavior behavior
Definition: parsenodes.h:3118
Definition: regguts.h:318
static void DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
Definition: tablecmds.c:1260
static void RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
Definition: tablecmds.c:1499

References AcceptInvalidationMessages(), AccessExclusiveLock, add_exact_object_address(), Assert(), DropStmt::behavior, ObjectAddress::classId, DropStmt::concurrent, DROP_CASCADE, DropErrorMsgNonExistent(), elog(), ereport, errcode(), errmsg(), ERROR, find_all_inheritors(), free_object_addresses(), InvalidOid, lfirst, list_length(), makeRangeVarFromNameList(), DropStmt::missing_ok, new_object_addresses(), OBJECT_FOREIGN_TABLE, OBJECT_INDEX, OBJECT_MATVIEW, OBJECT_SEQUENCE, OBJECT_TABLE, OBJECT_VIEW, ObjectAddress::objectId, DropStmt::objects, ObjectAddress::objectSubId, OidIsValid, PERFORM_DELETION_CONCURRENTLY, performMultipleDeletions(), RangeVarCallbackForDropRelation(), RangeVarGetRelidExtended(), RangeVar::relname, DropStmt::removeType, RVR_MISSING_OK, and ShareUpdateExclusiveLock.

Referenced by ExecDropStmt().

◆ renameatt()

ObjectAddress renameatt ( RenameStmt stmt)

Definition at line 3588 of file tablecmds.c.

3589 {
3590  Oid relid;
3592  ObjectAddress address;
3593 
3594  /* lock level taken here should match renameatt_internal */
3596  stmt->missing_ok ? RVR_MISSING_OK : 0,
3598  NULL);
3599 
3600  if (!OidIsValid(relid))
3601  {
3602  ereport(NOTICE,
3603  (errmsg("relation \"%s\" does not exist, skipping",
3604  stmt->relation->relname)));
3605  return InvalidObjectAddress;
3606  }
3607 
3608  attnum =
3609  renameatt_internal(relid,
3610  stmt->subname, /* old att name */
3611  stmt->newname, /* new att name */
3612  stmt->relation->inh, /* recursive? */
3613  false, /* recursing? */
3614  0, /* expected inhcount */
3615  stmt->behavior);
3616 
3617  ObjectAddressSubSet(address, RelationRelationId, relid, attnum);
3618 
3619  return address;
3620 }
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
RangeVar * relation
Definition: parsenodes.h:3408
bool missing_ok
Definition: parsenodes.h:3414
DropBehavior behavior
Definition: parsenodes.h:3413
char * newname
Definition: parsenodes.h:3412
char * subname
Definition: parsenodes.h:3410
static AttrNumber renameatt_internal(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
Definition: tablecmds.c:3423
static void RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:3568

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

Referenced by ExecRenameStmt().

◆ RenameConstraint()

ObjectAddress RenameConstraint ( RenameStmt stmt)

Definition at line 3732 of file tablecmds.c.

3733 {
3734  Oid relid = InvalidOid;
3735  Oid typid = InvalidOid;
3736 
3737  if (stmt->renameType == OBJECT_DOMCONSTRAINT)
3738  {
3739  Relation rel;
3740  HeapTuple tup;
3741 
3743  rel = table_open(TypeRelationId, RowExclusiveLock);
3744  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3745  if (!HeapTupleIsValid(tup))
3746  elog(ERROR, "cache lookup failed for type %u", typid);
3747  checkDomainOwner(tup);
3748  ReleaseSysCache(tup);
3749  table_close(rel, NoLock);
3750  }
3751  else
3752  {
3753  /* lock level taken here should match rename_constraint_internal */
3755  stmt->missing_ok ? RVR_MISSING_OK : 0,
3757  NULL);
3758  if (!OidIsValid(relid))
3759  {
3760  ereport(NOTICE,
3761  (errmsg("relation \"%s\" does not exist, skipping",
3762  stmt->relation->relname)));
3763  return InvalidObjectAddress;
3764  }
3765  }
3766 
3767  return
3768  rename_constraint_internal(relid, typid,
3769  stmt->subname,
3770  stmt->newname,
3771  (stmt->relation &&
3772  stmt->relation->inh), /* recursive? */
3773  false, /* recursing? */
3774  0 /* expected inhcount */ );
3775 }
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:457
#define castNode(_type_, nodeptr)
Definition: nodes.h:643
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2148
ObjectType renameType
Definition: parsenodes.h:3406
Node * object
Definition: parsenodes.h:3409
@ TYPEOID
Definition: syscache.h:114
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:3626
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3422

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

Referenced by ExecRenameStmt().

◆ RenameRelation()

ObjectAddress RenameRelation ( RenameStmt stmt)

Definition at line 3782 of file tablecmds.c.

3783 {
3784  bool is_index_stmt = stmt->renameType == OBJECT_INDEX;
3785  Oid relid;
3786  ObjectAddress address;
3787 
3788  /*
3789  * Grab an exclusive lock on the target table, index, sequence, view,
3790  * materialized view, or foreign table, which we will NOT release until
3791  * end of transaction.
3792  *
3793  * Lock level used here should match RenameRelationInternal, to avoid lock
3794  * escalation. However, because ALTER INDEX can be used with any relation
3795  * type, we mustn't believe without verification.
3796  */
3797  for (;;)
3798  {
3799  LOCKMODE lockmode;
3800  char relkind;
3801  bool obj_is_index;
3802 
3803  lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock;
3804 
3805  relid = RangeVarGetRelidExtended(stmt->relation, lockmode,
3806  stmt->missing_ok ? RVR_MISSING_OK : 0,
3808  (void *) stmt);
3809 
3810  if (!OidIsValid(relid))
3811  {
3812  ereport(NOTICE,
3813  (errmsg("relation \"%s\" does not exist, skipping",
3814  stmt->relation->relname)));
3815  return InvalidObjectAddress;
3816  }
3817 
3818  /*
3819  * We allow mismatched statement and object types (e.g., ALTER INDEX
3820  * to rename a table), but we might've used the wrong lock level. If
3821  * that happens, retry with the correct lock level. We don't bother
3822  * if we already acquired AccessExclusiveLock with an index, however.
3823  */
3824  relkind = get_rel_relkind(relid);
3825  obj_is_index = (relkind == RELKIND_INDEX ||
3826  relkind == RELKIND_PARTITIONED_INDEX);
3827  if (obj_is_index || is_index_stmt == obj_is_index)
3828  break;
3829 
3830  UnlockRelationOid(relid, lockmode);
3831  is_index_stmt = obj_is_index;
3832  }
3833 
3834  /* Do the work */
3835  RenameRelationInternal(relid, stmt->newname, false, is_index_stmt);
3836 
3837  ObjectAddressSet(address, RelationRelationId, relid);
3838 
3839  return address;
3840 }
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:228
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3846

References AccessExclusiveLock, ereport, errmsg(), get_rel_relkind(), InvalidObjectAddress, RenameStmt::missing_ok, RenameStmt::newname, NOTICE, OBJECT_INDEX, ObjectAddressSet, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetRelidExtended(), RenameStmt::relation, RenameRelationInternal(), RenameStmt::renameType, RVR_MISSING_OK, ShareUpdateExclusiveLock, and UnlockRelationOid().

Referenced by ExecRenameStmt().

◆ RenameRelationInternal()

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

Definition at line 3846 of file tablecmds.c.

3847 {
3848  Relation targetrelation;
3849  Relation relrelation; /* for RELATION relation */
3850  HeapTuple reltup;
3851  Form_pg_class relform;
3852  Oid namespaceId;
3853 
3854  /*
3855  * Grab a lock on the target relation, which we will NOT release until end
3856  * of transaction. We need at least a self-exclusive lock so that
3857  * concurrent DDL doesn't overwrite the rename if they start updating
3858  * while still seeing the old version. The lock also guards against
3859  * triggering relcache reloads in concurrent sessions, which might not
3860  * handle this information changing under them. For indexes, we can use a
3861  * reduced lock level because RelationReloadIndexInfo() handles indexes
3862  * specially.
3863  */
3864  targetrelation = relation_open(myrelid, is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock);
3865  namespaceId = RelationGetNamespace(targetrelation);
3866 
3867  /*
3868  * Find relation's pg_class tuple, and make sure newrelname isn't in use.
3869  */
3870  relrelation = table_open(RelationRelationId, RowExclusiveLock);
3871 
3872  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3873  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3874  elog(ERROR, "cache lookup failed for relation %u", myrelid);
3875  relform = (Form_pg_class) GETSTRUCT(reltup);
3876 
3877  if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
3878  ereport(ERROR,
3879  (errcode(ERRCODE_DUPLICATE_TABLE),
3880  errmsg("relation \"%s\" already exists",
3881  newrelname)));
3882 
3883  /*
3884  * RenameRelation is careful not to believe the caller's idea of the
3885  * relation kind being handled. We don't have to worry about this, but
3886  * let's not be totally oblivious to it. We can process an index as
3887  * not-an-index, but not the other way around.
3888  */
3889  Assert(!is_index ||
3890  is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3891  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX));
3892 
3893  /*
3894  * Update pg_class tuple with new relname. (Scribbling on reltup is OK
3895  * because it's a copy...)
3896  */
3897  namestrcpy(&(relform->relname), newrelname);
3898 
3899  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3900 
3901  InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
3902  InvalidOid, is_internal);
3903 
3904  heap_freetuple(reltup);
3905  table_close(relrelation, RowExclusiveLock);
3906 
3907  /*
3908  * Also rename the associated type, if any.
3909  */
3910  if (OidIsValid(targetrelation->rd_rel->reltype))
3911  RenameTypeInternal(targetrelation->rd_rel->reltype,
3912  newrelname, namespaceId);
3913 
3914  /*
3915  * Also rename the associated constraint, if any.
3916  */
3917  if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
3918  targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
3919  {
3920  Oid constraintId = get_index_constraint(myrelid);
3921 
3922  if (OidIsValid(constraintId))
3923  RenameConstraintById(constraintId, newrelname);
3924  }
3925 
3926  /*
3927  * Close rel, but keep lock!
3928  */
3929  relation_close(targetrelation, NoLock);
3930 }
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define InvokeObjectPostAlterHookArg(classId, objectId, subId, auxiliaryId, is_internal)
Definition: objectaccess.h:198
void RenameConstraintById(Oid conId, const char *newname)
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:911
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:741

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

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

◆ ResetRelRewrite()

void ResetRelRewrite ( Oid  myrelid)

Definition at line 3936 of file tablecmds.c.

3937 {
3938  Relation relrelation; /* for RELATION relation */
3939  HeapTuple reltup;
3940  Form_pg_class relform;
3941 
3942  /*
3943  * Find relation's pg_class tuple.
3944  */
3945  relrelation = table_open(RelationRelationId, RowExclusiveLock);
3946 
3947  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
3948  if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
3949  elog(ERROR, "cache lookup failed for relation %u", myrelid);
3950  relform = (Form_pg_class) GETSTRUCT(reltup);
3951 
3952  /*
3953  * Update pg_class tuple.
3954  */
3955  relform->relrewrite = InvalidOid;
3956 
3957  CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
3958 
3959  heap_freetuple(reltup);
3960  table_close(relrelation, RowExclusiveLock);
3961 }

References CatalogTupleUpdate(), elog(), ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvalidOid, ObjectIdGetDatum, RELOID, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

Referenced by finish_heap_swap().

◆ SetRelationHasSubclass()

void SetRelationHasSubclass ( Oid  relationId,
bool  relhassubclass 
)

Definition at line 3234 of file tablecmds.c.

3235 {
3236  Relation relationRelation;
3237  HeapTuple tuple;
3238  Form_pg_class classtuple;
3239 
3240  /*
3241  * Fetch a modifiable copy of the tuple, modify it, update pg_class.
3242  */
3243  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
3244  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relationId));
3245  if (!HeapTupleIsValid(tuple))
3246  elog(ERROR, "cache lookup failed for relation %u", relationId);
3247  classtuple = (Form_pg_class) GETSTRUCT(tuple);
3248 
3249  if (classtuple->relhassubclass != relhassubclass)
3250  {
3251  classtuple->relhassubclass = relhassubclass;
3252  CatalogTupleUpdate(relationRelation, &tuple->t_self, tuple);
3253  }
3254  else
3255  {
3256  /* no need to change tuple, but force relcache rebuild anyway */
3258  }
3259 
3260  heap_freetuple(tuple);
3261  table_close(relationRelation, RowExclusiveLock);
3262 }
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Definition: inval.c:1399

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

Referenced by acquire_inherited_sample_rows(), index_create(), IndexSetParentIndex(), and StoreCatalogInheritance1().

◆ SetRelationTableSpace()

void SetRelationTableSpace ( Relation  rel,
Oid  newTableSpaceId,
Oid  newRelFileNode 
)

Definition at line 3332 of file tablecmds.c.

3335 {
3336  Relation pg_class;
3337  HeapTuple tuple;
3338  Form_pg_class rd_rel;
3339  Oid reloid = RelationGetRelid(rel);
3340 
3341  Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3342 
3343  /* Get a modifiable copy of the relation's pg_class row. */
3344  pg_class = table_open(RelationRelationId, RowExclusiveLock);
3345 
3346  tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
3347  if (!HeapTupleIsValid(tuple))
3348  elog(ERROR, "cache lookup failed for relation %u", reloid);
3349  rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3350 
3351  /* Update the pg_class row. */
3352  rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3353  InvalidOid : newTableSpaceId;
3354  if (OidIsValid(newRelFileNode))
3355  rd_rel->relfilenode = newRelFileNode;
3356  CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3357 
3358  /*
3359  * Record dependency on tablespace. This is only required for relations
3360  * that have no physical storage.
3361  */
3362  if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3363  changeDependencyOnTablespace(RelationRelationId, reloid,
3364  rd_rel->reltablespace);
3365 
3366  heap_freetuple(tuple);
3367  table_close(pg_class, RowExclusiveLock);
3368 }
void changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId)
Definition: pg_shdepend.c:381
bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
Definition: tablecmds.c:3275

References Assert(), CatalogTupleUpdate(), changeDependencyOnTablespace(), CheckRelationTableSpaceMove(), elog(), ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvalidOid, MyDatabaseTableSpace, ObjectIdGetDatum, OidIsValid, RelationData::rd_rel, RelationGetRelid, RELOID, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

Referenced by ATExecSetTableSpace(), ATExecSetTableSpaceNoStorage(), and reindex_index().