PostgreSQL Source Code  git master
tablecmds.c File Reference
#include "postgres.h"
#include "access/attmap.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/heapam_xlog.h"
#include "access/multixact.h"
#include "access/reloptions.h"
#include "access/relscan.h"
#include "access/sysattr.h"
#include "access/tableam.h"
#include "access/toast_compression.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "catalog/catalog.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_largeobject.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "catalog/toasting.h"
#include "commands/cluster.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/policy.h"
#include "commands/sequence.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
#include "commands/user.h"
#include "commands/vacuum.h"
#include "executor/executor.h"
#include "foreign/fdwapi.h"
#include "foreign/foreign.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/parsenodes.h"
#include "optimizer/optimizer.h"
#include "parser/parse_clause.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "parser/parse_utilcmd.h"
#include "parser/parser.h"
#include "partitioning/partbounds.h"
#include "partitioning/partdesc.h"
#include "pgstat.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteHandler.h"
#include "rewrite/rewriteManip.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "storage/lock.h"
#include "storage/predicate.h"
#include "storage/smgr.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/partcache.h"
#include "utils/relcache.h"
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/timestamp.h"
#include "utils/typcache.h"
#include "utils/usercontext.h"
Include dependency graph for tablecmds.c:

Go to the source code of this file.

Data Structures

struct  OnCommitItem
 
struct  AlteredTableInfo
 
struct  NewConstraint
 
struct  NewColumnValue
 
struct  dropmsgstrings
 
struct  DropRelationCallbackState
 
struct  ForeignTruncateInfo
 
struct  AttachIndexCallbackState
 

Macros

#define AT_PASS_UNSET   -1 /* UNSET will cause ERROR */
 
#define AT_PASS_DROP   0 /* DROP (all flavors) */
 
#define AT_PASS_ALTER_TYPE   1 /* ALTER COLUMN TYPE */
 
#define AT_PASS_OLD_INDEX   2 /* re-add existing indexes */
 
#define AT_PASS_OLD_CONSTR   3 /* re-add existing constraints */
 
#define AT_PASS_ADD_COL   4 /* ADD COLUMN */
 
#define AT_PASS_ADD_CONSTR   5 /* ADD constraints (initial examination) */
 
#define AT_PASS_COL_ATTRS   6 /* set column attributes, eg NOT NULL */
 
#define AT_PASS_ADD_INDEXCONSTR   7 /* ADD index-based constraints */
 
#define AT_PASS_ADD_INDEX   8 /* ADD indexes */
 
#define AT_PASS_ADD_OTHERCONSTR   9 /* ADD other constraints, defaults */
 
#define AT_PASS_MISC   10 /* other stuff */
 
#define AT_NUM_PASSES   11
 
#define ATT_TABLE   0x0001
 
#define ATT_VIEW   0x0002
 
#define ATT_MATVIEW   0x0004
 
#define ATT_INDEX   0x0008
 
#define ATT_COMPOSITE_TYPE   0x0010
 
#define ATT_FOREIGN_TABLE   0x0020
 
#define ATT_PARTITIONED_INDEX   0x0040
 
#define ATT_SEQUENCE   0x0080
 
#define child_dependency_type(child_is_partition)    ((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
 

Typedefs

typedef struct OnCommitItem OnCommitItem
 
typedef struct AlteredTableInfo AlteredTableInfo
 
typedef struct NewConstraint NewConstraint
 
typedef struct NewColumnValue NewColumnValue
 
typedef struct ForeignTruncateInfo ForeignTruncateInfo
 

Functions

static void truncate_check_rel (Oid relid, Form_pg_class reltuple)
 
static void truncate_check_perms (Oid relid, Form_pg_class reltuple)
 
static void truncate_check_activity (Relation rel)
 
static void RangeVarCallbackForTruncate (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
static ListMergeAttributes (List *columns, const List *supers, char relpersistence, bool is_partition, List **supconstr, List **supnotnulls)
 
static ListMergeCheckConstraint (List *constraints, const char *name, Node *expr)
 
static void MergeAttributesIntoExisting (Relation child_rel, Relation parent_rel)
 
static void MergeConstraintsIntoExisting (Relation child_rel, Relation parent_rel)
 
static void StoreCatalogInheritance (Oid relationId, List *supers, bool child_is_partition)
 
static void StoreCatalogInheritance1 (Oid relationId, Oid parentOid, int32 seqNumber, Relation inhRelation, bool child_is_partition)
 
static int findAttrByName (const char *attributeName, const List *columns)
 
static void AlterIndexNamespaces (Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
 
static void AlterSeqNamespaces (Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
 
static ObjectAddress ATExecAlterConstraint (Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
 
static bool ATExecAlterConstrRecurse (Constraint *cmdcon, Relation conrel, Relation tgrel, Relation rel, HeapTuple contuple, List **otherrelids, LOCKMODE lockmode)
 
static ObjectAddress ATExecValidateConstraint (List **wqueue, Relation rel, char *constrName, bool recurse, bool recursing, LOCKMODE lockmode)
 
static int transformColumnNameList (Oid relId, List *colList, int16 *attnums, Oid *atttypids)
 
static int transformFkeyGetPrimaryKey (Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
 
static Oid transformFkeyCheckAttrs (Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
 
static void checkFkeyPermissions (Relation rel, int16 *attnums, int natts)
 
static CoercionPathType findFkeyCast (Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
 
static void validateForeignKeyConstraint (char *conname, Relation rel, Relation pkrel, Oid pkindOid, Oid constraintOid)
 
static void ATController (AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATPrepCmd (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATRewriteCatalogs (List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATExecCmd (List **wqueue, AlteredTableInfo *tab, AlterTableCmd *cmd, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
 
static AlterTableCmdATParseTransformCmd (List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
 
static void ATRewriteTables (AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATRewriteTable (AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 
static AlteredTableInfoATGetQueueEntry (List **wqueue, Relation rel)
 
static void ATSimplePermissions (AlterTableType cmdtype, Relation rel, int allowed_targets)
 
static void ATSimpleRecursion (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATCheckPartitionsNotInUse (Relation rel, LOCKMODE lockmode)
 
static void ATTypedTableRecursion (List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static Listfind_typed_table_dependencies (Oid typeOid, const char *typeName, DropBehavior behavior)
 
static void ATPrepAddColumn (List **wqueue, Relation rel, bool recurse, bool recursing, bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static ObjectAddress ATExecAddColumn (List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd **cmd, bool recurse, bool recursing, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
 
static bool check_for_column_name_collision (Relation rel, const char *colname, bool if_not_exists)
 
static void add_column_datatype_dependency (Oid relid, int32 attnum, Oid typid)
 
static void add_column_collation_dependency (Oid relid, int32 attnum, Oid collid)
 
static ObjectAddress ATExecDropNotNull (Relation rel, const char *colName, bool recurse, LOCKMODE lockmode)
 
static bool set_attnotnull (List **wqueue, Relation rel, AttrNumber attnum, bool recurse, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetNotNull (List **wqueue, Relation rel, char *constrname, char *colName, bool recurse, bool recursing, List **readyRels, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetAttNotNull (List **wqueue, Relation rel, const char *colName, LOCKMODE lockmode)
 
static bool NotNullImpliedByRelConstraints (Relation rel, Form_pg_attribute attr)
 
static bool ConstraintImpliedByRelConstraint (Relation scanrel, List *testConstraint, List *provenConstraint)
 
static ObjectAddress ATExecColumnDefault (Relation rel, const char *colName, Node *newDefault, LOCKMODE lockmode)
 
static ObjectAddress ATExecCookedColumnDefault (Relation rel, AttrNumber attnum, Node *newDefault)
 
static ObjectAddress ATExecAddIdentity (Relation rel, const char *colName, Node *def, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetIdentity (Relation rel, const char *colName, Node *def, LOCKMODE lockmode)
 
static ObjectAddress ATExecDropIdentity (Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
 
static void ATPrepDropExpression (Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
 
static ObjectAddress ATExecDropExpression (Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetStatistics (Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetOptions (Relation rel, const char *colName, Node *options, bool isReset, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetStorage (Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
 
static void ATPrepDropColumn (List **wqueue, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static ObjectAddress ATExecDropColumn (List **wqueue, Relation rel, const char *colName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode, ObjectAddresses *addrs)
 
static void ATPrepAddPrimaryKey (List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static ObjectAddress ATExecAddIndex (AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
 
static ObjectAddress ATExecAddStatistics (AlteredTableInfo *tab, Relation rel, CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
 
static ObjectAddress ATExecAddConstraint (List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *newConstraint, bool recurse, bool is_readd, LOCKMODE lockmode)
 
static char * ChooseForeignKeyConstraintNameAddition (List *colnames)
 
static ObjectAddress ATExecAddIndexConstraint (AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, LOCKMODE lockmode)
 
static ObjectAddress ATAddCheckNNConstraint (List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
 
static ObjectAddress ATAddForeignKeyConstraint (List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, bool recurse, bool recursing, LOCKMODE lockmode)
 
static ObjectAddress addFkRecurseReferenced (List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, Oid parentDelTrigger, Oid parentUpdTrigger)
 
static void validateFkOnDeleteSetColumns (int numfks, const int16 *fkattnums, int numfksetcols, const int16 *fksetcolsattnums, List *fksetcols)
 
static void addFkRecurseReferencing (List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, LOCKMODE lockmode, Oid parentInsTrigger, Oid parentUpdTrigger)
 
static void CloneForeignKeyConstraints (List **wqueue, Relation parentRel, Relation partitionRel)
 
static void CloneFkReferenced (Relation parentRel, Relation partitionRel)
 
static void CloneFkReferencing (List **wqueue, Relation parentRel, Relation partRel)
 
static void createForeignKeyCheckTriggers (Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
 
static void createForeignKeyActionTriggers (Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
 
static bool tryAttachPartitionForeignKey (ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop, Oid parentInsTrigger, Oid parentUpdTrigger, Relation trigrel)
 
static void GetForeignKeyActionTriggers (Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *deleteTriggerOid, Oid *updateTriggerOid)
 
static void GetForeignKeyCheckTriggers (Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *insertTriggerOid, Oid *updateTriggerOid)
 
static void ATExecDropConstraint (Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool missing_ok, LOCKMODE lockmode)
 
static ObjectAddress dropconstraint_internal (Relation rel, HeapTuple constraintTup, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, List **readyRels, LOCKMODE lockmode)
 
static void ATPrepAlterColumnType (List **wqueue, AlteredTableInfo *tab, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static bool ATColumnChangeRequiresRewrite (Node *expr, AttrNumber varattno)
 
static ObjectAddress ATExecAlterColumnType (AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static void RememberConstraintForRebuilding (Oid conoid, AlteredTableInfo *tab)
 
static void RememberIndexForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
static void RememberStatisticsForRebuilding (Oid stxoid, AlteredTableInfo *tab)
 
static void ATPostAlterTypeCleanup (List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
 
static void ATPostAlterTypeParse (Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, List **wqueue, LOCKMODE lockmode, bool rewrite)
 
static void RebuildConstraintComment (AlteredTableInfo *tab, int pass, Oid objid, Relation rel, List *domname, const char *conname)
 
static void TryReuseIndex (Oid oldId, IndexStmt *stmt)
 
static void TryReuseForeignKey (Oid oldId, Constraint *con)
 
static ObjectAddress ATExecAlterColumnGenericOptions (Relation rel, const char *colName, List *options, LOCKMODE lockmode)
 
static void change_owner_fix_column_acls (Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
 
static void change_owner_recurse_to_sequences (Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
 
static ObjectAddress ATExecClusterOn (Relation rel, const char *indexName, LOCKMODE lockmode)
 
static void ATExecDropCluster (Relation rel, LOCKMODE lockmode)
 
static void ATPrepSetAccessMethod (AlteredTableInfo *tab, Relation rel, const char *amname)
 
static bool ATPrepChangePersistence (Relation rel, bool toLogged)
 
static void ATPrepSetTableSpace (AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
 
static void ATExecSetTableSpace (Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 
static void ATExecSetTableSpaceNoStorage (Relation rel, Oid newTableSpace)
 
static void ATExecSetRelOptions (Relation rel, List *defList, AlterTableType operation, LOCKMODE lockmode)
 
static void ATExecEnableDisableTrigger (Relation rel, const char *trigname, char fires_when, bool skip_system, bool recurse, LOCKMODE lockmode)
 
static void ATExecEnableDisableRule (Relation rel, const char *rulename, char fires_when, LOCKMODE lockmode)
 
static void ATPrepAddInherit (Relation child_rel)
 
static ObjectAddress ATExecAddInherit (Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
 
static ObjectAddress ATExecDropInherit (Relation rel, RangeVar *parent, LOCKMODE lockmode)
 
static void drop_parent_dependency (Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
 
static ObjectAddress ATExecAddOf (Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
 
static void ATExecDropOf (Relation rel, LOCKMODE lockmode)
 
static void ATExecReplicaIdentity (Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
 
static void ATExecGenericOptions (Relation rel, List *options)
 
static void ATExecSetRowSecurity (Relation rel, bool rls)
 
static void ATExecForceNoForceRowSecurity (Relation rel, bool force_rls)
 
static ObjectAddress ATExecSetCompression (Relation rel, const char *column, Node *newValue, LOCKMODE lockmode)
 
static void index_copy_data (Relation rel, RelFileLocator newrlocator)
 
static const char * storage_name (char c)
 
static void RangeVarCallbackForDropRelation (const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
 
static void RangeVarCallbackForAlterRelation (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
static PartitionSpectransformPartitionSpec (Relation rel, PartitionSpec *partspec)
 
static void ComputePartitionAttrs (ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, PartitionStrategy strategy)
 
static void CreateInheritance (Relation child_rel, Relation parent_rel)
 
static void RemoveInheritance (Relation child_rel, Relation parent_rel, bool expect_detached)
 
static void ATInheritAdjustNotNulls (Relation parent_rel, Relation child_rel, int inhcount)
 
static ObjectAddress ATExecAttachPartition (List **wqueue, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
 
static void AttachPartitionEnsureIndexes (List **wqueue, Relation rel, Relation attachrel)
 
static void QueuePartitionConstraintValidation (List **wqueue, Relation scanrel, List *partConstraint, bool validate_default)
 
static void CloneRowTriggersToPartition (Relation parent, Relation partition)
 
static void DetachAddConstraintIfNeeded (List **wqueue, Relation partRel)
 
static void DropClonedTriggersFromPartition (Oid partitionId)
 
static ObjectAddress ATExecDetachPartition (List **wqueue, AlteredTableInfo *tab, Relation rel, RangeVar *name, bool concurrent)
 
static void DetachPartitionFinalize (Relation rel, Relation partRel, bool concurrent, Oid defaultPartOid)
 
static ObjectAddress ATExecDetachPartitionFinalize (Relation rel, RangeVar *name)
 
static ObjectAddress ATExecAttachPartitionIdx (List **wqueue, Relation parentIdx, RangeVar *name)
 
static void validatePartitionedIndex (Relation partedIdx, Relation partedTbl)
 
static void refuseDupeIndexAttach (Relation parentIdx, Relation partIdx, Relation partitionTbl)
 
static void verifyPartitionIndexNotNull (IndexInfo *iinfo, Relation partIdx)
 
static ListGetParentedForeignKeyRefs (Relation partition)
 
static void ATDetachCheckNoForeignKeyRefs (Relation partition)
 
static char GetAttributeCompression (Oid atttypid, const char *compression)
 
static char GetAttributeStorage (Oid atttypid, const char *storagemode)
 
ObjectAddress DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
 
static void DropErrorMsgNonExistent (RangeVar *rel, char rightkind, bool missing_ok)
 
static void DropErrorMsgWrongType (const char *relname, char wrongkind, char rightkind)
 
void RemoveRelations (DropStmt *drop)
 
void ExecuteTruncate (TruncateStmt *stmt)
 
void ExecuteTruncateGuts (List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs, bool run_as_table_owner)
 
void SetRelationHasSubclass (Oid relationId, bool relhassubclass)
 
bool CheckRelationTableSpaceMove (Relation rel, Oid newTableSpaceId)
 
void SetRelationTableSpace (Relation rel, Oid newTableSpaceId, RelFileNumber newRelFilenumber)
 
static void renameatt_check (Oid myrelid, Form_pg_class classform, bool recursing)
 
static AttrNumber renameatt_internal (Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
 
static void RangeVarCallbackForRenameAttribute (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
ObjectAddress renameatt (RenameStmt *stmt)
 
static ObjectAddress rename_constraint_internal (Oid myrelid, Oid mytypid, const char *oldconname, const char *newconname, bool recurse, bool recursing, int expected_parents)
 
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 CheckTableNotInUse (Relation rel, const char *stmt)
 
Oid AlterTableLookupRelation (AlterTableStmt *stmt, LOCKMODE lockmode)
 
void AlterTable (AlterTableStmt *stmt, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
void AlterTableInternal (Oid relid, List *cmds, bool recurse)
 
LOCKMODE AlterTableGetLockLevel (List *cmds)
 
static const char * alter_table_type_to_string (AlterTableType cmdtype)
 
void find_composite_type_dependencies (Oid typeOid, Relation origRelation, const char *origTypeName)
 
void check_of_type (HeapTuple typetuple)
 
static void SetIndexStorageProperties (Relation rel, Relation attrelation, AttrNumber attnum, bool setstorage, char newstorage, bool setcompression, char newcompression, LOCKMODE lockmode)
 
static Oid CreateFKCheckTrigger (Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentTrigOid, bool on_insert)
 
static void RememberReplicaIdentityForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
static void RememberClusterOnForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
void ATExecChangeOwner (Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
 
Oid AlterTableMoveAll (AlterTableMoveAllStmt *stmt)
 
static char * decompile_conbin (HeapTuple contup, TupleDesc tupdesc)
 
static bool constraints_equivalent (HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
 
static void MarkInheritDetached (Relation child_rel, Relation parent_rel)
 
static void relation_mark_replica_identity (Relation rel, char ri_type, Oid indexOid, bool is_internal)
 
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 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)
 
static void RangeVarCallbackForAttachIndex (const RangeVar *rv, Oid relOid, Oid oldRelOid, void *arg)
 

Variables

static Liston_commits = NIL
 
static const struct dropmsgstrings dropmsgstringarray []
 

Macro Definition Documentation

◆ AT_NUM_PASSES

#define AT_NUM_PASSES   11

Definition at line 158 of file tablecmds.c.

◆ AT_PASS_ADD_COL

#define AT_PASS_ADD_COL   4 /* ADD COLUMN */

Definition at line 151 of file tablecmds.c.

◆ AT_PASS_ADD_CONSTR

#define AT_PASS_ADD_CONSTR   5 /* ADD constraints (initial examination) */

Definition at line 152 of file tablecmds.c.

◆ AT_PASS_ADD_INDEX

#define AT_PASS_ADD_INDEX   8 /* ADD indexes */

Definition at line 155 of file tablecmds.c.

◆ AT_PASS_ADD_INDEXCONSTR

#define AT_PASS_ADD_INDEXCONSTR   7 /* ADD index-based constraints */

Definition at line 154 of file tablecmds.c.

◆ AT_PASS_ADD_OTHERCONSTR

#define AT_PASS_ADD_OTHERCONSTR   9 /* ADD other constraints, defaults */

Definition at line 156 of file tablecmds.c.

◆ AT_PASS_ALTER_TYPE

#define AT_PASS_ALTER_TYPE   1 /* ALTER COLUMN TYPE */

Definition at line 147 of file tablecmds.c.

◆ AT_PASS_COL_ATTRS

#define AT_PASS_COL_ATTRS   6 /* set column attributes, eg NOT NULL */

Definition at line 153 of file tablecmds.c.

◆ AT_PASS_DROP

#define AT_PASS_DROP   0 /* DROP (all flavors) */

Definition at line 146 of file tablecmds.c.

◆ AT_PASS_MISC

#define AT_PASS_MISC   10 /* other stuff */

Definition at line 157 of file tablecmds.c.

◆ AT_PASS_OLD_CONSTR

#define AT_PASS_OLD_CONSTR   3 /* re-add existing constraints */

Definition at line 149 of file tablecmds.c.

◆ AT_PASS_OLD_INDEX

#define AT_PASS_OLD_INDEX   2 /* re-add existing indexes */

Definition at line 148 of file tablecmds.c.

◆ AT_PASS_UNSET

#define AT_PASS_UNSET   -1 /* UNSET will cause ERROR */

Definition at line 145 of file tablecmds.c.

◆ ATT_COMPOSITE_TYPE

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 321 of file tablecmds.c.

◆ ATT_FOREIGN_TABLE

#define ATT_FOREIGN_TABLE   0x0020

Definition at line 322 of file tablecmds.c.

◆ ATT_INDEX

#define ATT_INDEX   0x0008

Definition at line 320 of file tablecmds.c.

◆ ATT_MATVIEW

#define ATT_MATVIEW   0x0004

Definition at line 319 of file tablecmds.c.

◆ ATT_PARTITIONED_INDEX

#define ATT_PARTITIONED_INDEX   0x0040

Definition at line 323 of file tablecmds.c.

◆ ATT_SEQUENCE

#define ATT_SEQUENCE   0x0080

Definition at line 324 of file tablecmds.c.

◆ ATT_TABLE

#define ATT_TABLE   0x0001

Definition at line 317 of file tablecmds.c.

◆ ATT_VIEW

#define ATT_VIEW   0x0002

Definition at line 318 of file tablecmds.c.

◆ child_dependency_type

#define child_dependency_type (   child_is_partition)     ((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)

Definition at line 345 of file tablecmds.c.

Typedef Documentation

◆ AlteredTableInfo

◆ ForeignTruncateInfo

◆ NewColumnValue

◆ NewConstraint

typedef struct NewConstraint NewConstraint

◆ OnCommitItem

typedef struct OnCommitItem OnCommitItem

Function Documentation

◆ add_column_collation_dependency()

static void add_column_collation_dependency ( Oid  relid,
int32  attnum,
Oid  collid 
)
static

Definition at line 7357 of file tablecmds.c.

7358 {
7359  ObjectAddress myself,
7360  referenced;
7361 
7362  /* We know the default collation is pinned, so don't bother recording it */
7363  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7364  {
7365  myself.classId = RelationRelationId;
7366  myself.objectId = relid;
7367  myself.objectSubId = attnum;
7368  referenced.classId = CollationRelationId;
7369  referenced.objectId = collid;
7370  referenced.objectSubId = 0;
7371  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7372  }
7373 }
#define OidIsValid(objectId)
Definition: c.h:764
Oid collid
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int16 attnum
Definition: pg_attribute.h:74
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44

References attnum, ObjectAddress::classId, collid, DEPENDENCY_NORMAL, ObjectAddress::objectId, ObjectAddress::objectSubId, OidIsValid, and recordDependencyOn().

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

◆ add_column_datatype_dependency()

static void add_column_datatype_dependency ( Oid  relid,
int32  attnum,
Oid  typid 
)
static

Definition at line 7339 of file tablecmds.c.

7340 {
7341  ObjectAddress myself,
7342  referenced;
7343 
7344  myself.classId = RelationRelationId;
7345  myself.objectId = relid;
7346  myself.objectSubId = attnum;
7347  referenced.classId = TypeRelationId;
7348  referenced.objectId = typid;
7349  referenced.objectSubId = 0;
7350  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7351 }

References attnum, ObjectAddress::classId, DEPENDENCY_NORMAL, ObjectAddress::objectId, ObjectAddress::objectSubId, and recordDependencyOn().

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

◆ addFkRecurseReferenced()

static ObjectAddress addFkRecurseReferenced ( List **  wqueue,
Constraint fkconstraint,
Relation  rel,
Relation  pkrel,
Oid  indexOid,
Oid  parentConstr,
int  numfks,
int16 pkattnum,
int16 fkattnum,
Oid pfeqoperators,
Oid ppeqoperators,
Oid ffeqoperators,
int  numfkdelsetcols,
int16 fkdelsetcols,
bool  old_check_ok,
Oid  parentDelTrigger,
Oid  parentUpdTrigger 
)
static

Definition at line 9891 of file tablecmds.c.

9899 {
9900  ObjectAddress address;
9901  Oid constrOid;
9902  char *conname;
9903  bool conislocal;
9904  int coninhcount;
9905  bool connoinherit;
9906  Oid deleteTriggerOid,
9907  updateTriggerOid;
9908 
9909  /*
9910  * Verify relkind for each referenced partition. At the top level, this
9911  * is redundant with a previous check, but we need it when recursing.
9912  */
9913  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9914  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9915  ereport(ERROR,
9916  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9917  errmsg("referenced relation \"%s\" is not a table",
9918  RelationGetRelationName(pkrel))));
9919 
9920  /*
9921  * Caller supplies us with a constraint name; however, it may be used in
9922  * this partition, so come up with a different one in that case.
9923  */
9925  RelationGetRelid(rel),
9926  fkconstraint->conname))
9929  "fkey",
9930  RelationGetNamespace(rel), NIL);
9931  else
9932  conname = fkconstraint->conname;
9933 
9934  if (OidIsValid(parentConstr))
9935  {
9936  conislocal = false;
9937  coninhcount = 1;
9938  connoinherit = false;
9939  }
9940  else
9941  {
9942  conislocal = true;
9943  coninhcount = 0;
9944 
9945  /*
9946  * always inherit for partitioned tables, never for legacy inheritance
9947  */
9948  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
9949  }
9950 
9951  /*
9952  * Record the FK constraint in pg_constraint.
9953  */
9954  constrOid = CreateConstraintEntry(conname,
9955  RelationGetNamespace(rel),
9956  CONSTRAINT_FOREIGN,
9957  fkconstraint->deferrable,
9958  fkconstraint->initdeferred,
9959  fkconstraint->initially_valid,
9960  parentConstr,
9961  RelationGetRelid(rel),
9962  fkattnum,
9963  numfks,
9964  numfks,
9965  InvalidOid, /* not a domain constraint */
9966  indexOid,
9967  RelationGetRelid(pkrel),
9968  pkattnum,
9969  pfeqoperators,
9970  ppeqoperators,
9971  ffeqoperators,
9972  numfks,
9973  fkconstraint->fk_upd_action,
9974  fkconstraint->fk_del_action,
9975  fkdelsetcols,
9976  numfkdelsetcols,
9977  fkconstraint->fk_matchtype,
9978  NULL, /* no exclusion constraint */
9979  NULL, /* no check constraint */
9980  NULL,
9981  conislocal, /* islocal */
9982  coninhcount, /* inhcount */
9983  connoinherit, /* conNoInherit */
9984  false); /* is_internal */
9985 
9986  ObjectAddressSet(address, ConstraintRelationId, constrOid);
9987 
9988  /*
9989  * Mark the child constraint as part of the parent constraint; it must not
9990  * be dropped on its own. (This constraint is deleted when the partition
9991  * is detached, but a special check needs to occur that the partition
9992  * contains no referenced values.)
9993  */
9994  if (OidIsValid(parentConstr))
9995  {
9996  ObjectAddress referenced;
9997 
9998  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9999  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
10000  }
10001 
10002  /* make new constraint visible, in case we add more */
10004 
10005  /*
10006  * Create the action triggers that enforce the constraint.
10007  */
10009  fkconstraint,
10010  constrOid, indexOid,
10011  parentDelTrigger, parentUpdTrigger,
10012  &deleteTriggerOid, &updateTriggerOid);
10013 
10014  /*
10015  * If the referenced table is partitioned, recurse on ourselves to handle
10016  * each partition. We need one pg_constraint row created for each
10017  * partition in addition to the pg_constraint row for the parent table.
10018  */
10019  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10020  {
10021  PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
10022 
10023  for (int i = 0; i < pd->nparts; i++)
10024  {
10025  Relation partRel;
10026  AttrMap *map;
10027  AttrNumber *mapped_pkattnum;
10028  Oid partIndexId;
10029 
10030  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
10031 
10032  /*
10033  * Map the attribute numbers in the referenced side of the FK
10034  * definition to match the partition's column layout.
10035  */
10037  RelationGetDescr(pkrel),
10038  false);
10039  if (map)
10040  {
10041  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
10042  for (int j = 0; j < numfks; j++)
10043  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
10044  }
10045  else
10046  mapped_pkattnum = pkattnum;
10047 
10048  /* do the deed */
10049  partIndexId = index_get_partition(partRel, indexOid);
10050  if (!OidIsValid(partIndexId))
10051  elog(ERROR, "index for %u not found in partition %s",
10052  indexOid, RelationGetRelationName(partRel));
10053  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
10054  partIndexId, constrOid, numfks,
10055  mapped_pkattnum, fkattnum,
10056  pfeqoperators, ppeqoperators, ffeqoperators,
10057  numfkdelsetcols, fkdelsetcols,
10058  old_check_ok,
10059  deleteTriggerOid, updateTriggerOid);
10060 
10061  /* Done -- clean up (but keep the lock) */
10062  table_close(partRel, NoLock);
10063  if (map)
10064  {
10065  pfree(mapped_pkattnum);
10066  free_attrmap(map);
10067  }
10068  }
10069  }
10070 
10071  return address;
10072 }
void free_attrmap(AttrMap *map)
Definition: attmap.c:57
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:264
int16 AttrNumber
Definition: attnum.h:21
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int j
Definition: isn.c:74
int i
Definition: isn.c:73
#define NoLock
Definition: lockdefs.h:34
#define ShareRowExclusiveLock
Definition: lockdefs.h:41
void pfree(void *pointer)
Definition: mcxt.c:1456
void * palloc(Size size)
Definition: mcxt.c:1226
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:72
Oid index_get_partition(Relation partition, Oid indexId)
Definition: partition.c:175
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:51
@ CONSTRAINT_RELATION
#define NIL
Definition: pg_list.h:68
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetRelid(relation)
Definition: rel.h:504
#define RelationGetDescr(relation)
Definition: rel.h:530
#define RelationGetRelationName(relation)
Definition: rel.h:538
#define RelationGetNamespace(relation)
Definition: rel.h:545
Definition: attmap.h:35
AttrNumber * attnums
Definition: attmap.h:36
bool initdeferred
Definition: parsenodes.h:2600
char fk_upd_action
Definition: parsenodes.h:2637
char fk_matchtype
Definition: parsenodes.h:2636
bool initially_valid
Definition: parsenodes.h:2646
bool deferrable
Definition: parsenodes.h:2599
char * conname
Definition: parsenodes.h:2598
char fk_del_action
Definition: parsenodes.h:2638
List * fk_attrs
Definition: parsenodes.h:2634
Form_pg_class rd_rel
Definition: rel.h:111
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:9207
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12087
static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, Oid parentDelTrigger, Oid parentUpdTrigger)
Definition: tablecmds.c:9891
void CommandCounterIncrement(void)
Definition: xact.c:1078

References AttrMap::attnums, build_attrmap_by_name_if_req(), ChooseConstraintName(), ChooseForeignKeyConstraintNameAddition(), CommandCounterIncrement(), Constraint::conname, CONSTRAINT_RELATION, ConstraintNameIsUsed(), CreateConstraintEntry(), createForeignKeyActionTriggers(), Constraint::deferrable, DEPENDENCY_INTERNAL, elog(), ereport, errcode(), errmsg(), ERROR, Constraint::fk_attrs, Constraint::fk_del_action, Constraint::fk_matchtype, Constraint::fk_upd_action, free_attrmap(), i, index_get_partition(), Constraint::initdeferred, Constraint::initially_valid, InvalidOid, j, NIL, NoLock, PartitionDescData::nparts, ObjectAddressSet, OidIsValid, PartitionDescData::oids, palloc(), pfree(), RelationData::rd_rel, recordDependencyOn(), RelationGetDescr, RelationGetNamespace, RelationGetPartitionDesc(), RelationGetRelationName, RelationGetRelid, ShareRowExclusiveLock, table_close(), and table_open().

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferenced().

◆ addFkRecurseReferencing()

static void addFkRecurseReferencing ( List **  wqueue,
Constraint fkconstraint,
Relation  rel,
Relation  pkrel,
Oid  indexOid,
Oid  parentConstr,
int  numfks,
int16 pkattnum,
int16 fkattnum,
Oid pfeqoperators,
Oid ppeqoperators,
Oid ffeqoperators,
int  numfkdelsetcols,
int16 fkdelsetcols,
bool  old_check_ok,
LOCKMODE  lockmode,
Oid  parentInsTrigger,
Oid  parentUpdTrigger 
)
static

Definition at line 10111 of file tablecmds.c.

10118 {
10119  Oid insertTriggerOid,
10120  updateTriggerOid;
10121 
10122  Assert(OidIsValid(parentConstr));
10123 
10124  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
10125  ereport(ERROR,
10126  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10127  errmsg("foreign key constraints are not supported on foreign tables")));
10128 
10129  /*
10130  * Add the check triggers to it and, if necessary, schedule it to be
10131  * checked in Phase 3.
10132  *
10133  * If the relation is partitioned, drill down to do it to its partitions.
10134  */
10136  RelationGetRelid(pkrel),
10137  fkconstraint,
10138  parentConstr,
10139  indexOid,
10140  parentInsTrigger, parentUpdTrigger,
10141  &insertTriggerOid, &updateTriggerOid);
10142 
10143  if (rel->rd_rel->relkind == RELKIND_RELATION)
10144  {
10145  /*
10146  * Tell Phase 3 to check that the constraint is satisfied by existing
10147  * rows. We can skip this during table creation, when requested
10148  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
10149  * and when we're recreating a constraint following a SET DATA TYPE
10150  * operation that did not impugn its validity.
10151  */
10152  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
10153  {
10154  NewConstraint *newcon;
10155  AlteredTableInfo *tab;
10156 
10157  tab = ATGetQueueEntry(wqueue, rel);
10158 
10159  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
10160  newcon->name = get_constraint_name(parentConstr);
10161  newcon->contype = CONSTR_FOREIGN;
10162  newcon->refrelid = RelationGetRelid(pkrel);
10163  newcon->refindid = indexOid;
10164  newcon->conid = parentConstr;
10165  newcon->qual = (Node *) fkconstraint;
10166 
10167  tab->constraints = lappend(tab->constraints, newcon);
10168  }
10169  }
10170  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10171  {
10172  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
10173  Relation trigrel;
10174 
10175  /*
10176  * Triggers of the foreign keys will be manipulated a bunch of times
10177  * in the loop below. To avoid repeatedly opening/closing the trigger
10178  * catalog relation, we open it here and pass it to the subroutines
10179  * called below.
10180  */
10181  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10182 
10183  /*
10184  * Recurse to take appropriate action on each partition; either we
10185  * find an existing constraint to reparent to ours, or we create a new
10186  * one.
10187  */
10188  for (int i = 0; i < pd->nparts; i++)
10189  {
10190  Oid partitionId = pd->oids[i];
10191  Relation partition = table_open(partitionId, lockmode);
10192  List *partFKs;
10193  AttrMap *attmap;
10194  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
10195  bool attached;
10196  char *conname;
10197  Oid constrOid;
10198  ObjectAddress address,
10199  referenced;
10200  ListCell *cell;
10201 
10202  CheckTableNotInUse(partition, "ALTER TABLE");
10203 
10204  attmap = build_attrmap_by_name(RelationGetDescr(partition),
10205  RelationGetDescr(rel),
10206  false);
10207  for (int j = 0; j < numfks; j++)
10208  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
10209 
10210  /* Check whether an existing constraint can be repurposed */
10211  partFKs = copyObject(RelationGetFKeyList(partition));
10212  attached = false;
10213  foreach(cell, partFKs)
10214  {
10215  ForeignKeyCacheInfo *fk;
10216 
10217  fk = lfirst_node(ForeignKeyCacheInfo, cell);
10219  partitionId,
10220  parentConstr,
10221  numfks,
10222  mapped_fkattnum,
10223  pkattnum,
10224  pfeqoperators,
10225  insertTriggerOid,
10226  updateTriggerOid,
10227  trigrel))
10228  {
10229  attached = true;
10230  break;
10231  }
10232  }
10233  if (attached)
10234  {
10235  table_close(partition, NoLock);
10236  continue;
10237  }
10238 
10239  /*
10240  * No luck finding a good constraint to reuse; create our own.
10241  */
10243  RelationGetRelid(partition),
10244  fkconstraint->conname))
10245  conname = ChooseConstraintName(RelationGetRelationName(partition),
10247  "fkey",
10248  RelationGetNamespace(partition), NIL);
10249  else
10250  conname = fkconstraint->conname;
10251  constrOid =
10252  CreateConstraintEntry(conname,
10253  RelationGetNamespace(partition),
10254  CONSTRAINT_FOREIGN,
10255  fkconstraint->deferrable,
10256  fkconstraint->initdeferred,
10257  fkconstraint->initially_valid,
10258  parentConstr,
10259  partitionId,
10260  mapped_fkattnum,
10261  numfks,
10262  numfks,
10263  InvalidOid,
10264  indexOid,
10265  RelationGetRelid(pkrel),
10266  pkattnum,
10267  pfeqoperators,
10268  ppeqoperators,
10269  ffeqoperators,
10270  numfks,
10271  fkconstraint->fk_upd_action,
10272  fkconstraint->fk_del_action,
10273  fkdelsetcols,
10274  numfkdelsetcols,
10275  fkconstraint->fk_matchtype,
10276  NULL,
10277  NULL,
10278  NULL,
10279  false,
10280  1,
10281  false,
10282  false);
10283 
10284  /*
10285  * Give this constraint partition-type dependencies on the parent
10286  * constraint as well as the table.
10287  */
10288  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10289  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
10290  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
10291  ObjectAddressSet(referenced, RelationRelationId, partitionId);
10292  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
10293 
10294  /* Make all this visible before recursing */
10296 
10297  /* call ourselves to finalize the creation and we're done */
10298  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
10299  indexOid,
10300  constrOid,
10301  numfks,
10302  pkattnum,
10303  mapped_fkattnum,
10304  pfeqoperators,
10305  ppeqoperators,
10306  ffeqoperators,
10307  numfkdelsetcols,
10308  fkdelsetcols,
10309  old_check_ok,
10310  lockmode,
10311  insertTriggerOid,
10312  updateTriggerOid);
10313 
10314  table_close(partition, NoLock);
10315  }
10316 
10317  table_close(trigrel, RowExclusiveLock);
10318  }
10319 }
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:178
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1107
void * palloc0(Size size)
Definition: mcxt.c:1257
#define copyObject(obj)
Definition: nodes.h:244
@ CONSTR_FOREIGN
Definition: parsenodes.h:2571
#define INDEX_MAX_KEYS
#define lfirst_node(type, lc)
Definition: pg_list.h:176
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4631
List * constraints
Definition: tablecmds.c:179
bool skip_validation
Definition: parsenodes.h:2645
Definition: pg_list.h:54
char * name
Definition: tablecmds.c:206
ConstrType contype
Definition: tablecmds.c:207
Node * qual
Definition: tablecmds.c:211
Definition: nodes.h:129
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:6216
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:4183
static bool tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop, Oid parentInsTrigger, Oid parentUpdTrigger, Relation trigrel)
Definition: tablecmds.c:10839
static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, LOCKMODE lockmode, Oid parentInsTrigger, Oid parentUpdTrigger)
Definition: tablecmds.c:10111
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12222

References Assert(), ATGetQueueEntry(), AttrMap::attnums, build_attrmap_by_name(), CheckTableNotInUse(), ChooseConstraintName(), ChooseForeignKeyConstraintNameAddition(), CommandCounterIncrement(), NewConstraint::conid, Constraint::conname, CONSTR_FOREIGN, CONSTRAINT_RELATION, ConstraintNameIsUsed(), AlteredTableInfo::constraints, NewConstraint::contype, copyObject, CreateConstraintEntry(), createForeignKeyCheckTriggers(), Constraint::deferrable, DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, ereport, errcode(), errmsg(), ERROR, Constraint::fk_attrs, Constraint::fk_del_action, Constraint::fk_matchtype, Constraint::fk_upd_action, get_constraint_name(), i, INDEX_MAX_KEYS, Constraint::initdeferred, Constraint::initially_valid, InvalidOid, j, lappend(), lfirst_node, NewConstraint::name, NIL, NoLock, PartitionDescData::nparts, ObjectAddressSet, OidIsValid, PartitionDescData::oids, palloc0(), NewConstraint::qual, RelationData::rd_rel, recordDependencyOn(), NewConstraint::refindid, NewConstraint::refrelid, RelationGetDescr, RelationGetFKeyList(), RelationGetNamespace, RelationGetPartitionDesc(), RelationGetRelationName, RelationGetRelid, RowExclusiveLock, Constraint::skip_validation, table_close(), table_open(), and tryAttachPartitionForeignKey().

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferencing().

◆ alter_table_type_to_string()

static const char* alter_table_type_to_string ( AlterTableType  cmdtype)
static

Definition at line 6249 of file tablecmds.c.

6250 {
6251  switch (cmdtype)
6252  {
6253  case AT_AddColumn:
6254  case AT_AddColumnToView:
6255  return "ADD COLUMN";
6256  case AT_ColumnDefault:
6258  return "ALTER COLUMN ... SET DEFAULT";
6259  case AT_DropNotNull:
6260  return "ALTER COLUMN ... DROP NOT NULL";
6261  case AT_SetNotNull:
6262  return "ALTER COLUMN ... SET NOT NULL";
6263  case AT_SetAttNotNull:
6264  return NULL; /* not real grammar */
6265  case AT_DropExpression:
6266  return "ALTER COLUMN ... DROP EXPRESSION";
6267  case AT_SetStatistics:
6268  return "ALTER COLUMN ... SET STATISTICS";
6269  case AT_SetOptions:
6270  return "ALTER COLUMN ... SET";
6271  case AT_ResetOptions:
6272  return "ALTER COLUMN ... RESET";
6273  case AT_SetStorage:
6274  return "ALTER COLUMN ... SET STORAGE";
6275  case AT_SetCompression:
6276  return "ALTER COLUMN ... SET COMPRESSION";
6277  case AT_DropColumn:
6278  return "DROP COLUMN";
6279  case AT_AddIndex:
6280  case AT_ReAddIndex:
6281  return NULL; /* not real grammar */
6282  case AT_AddConstraint:
6283  case AT_ReAddConstraint:
6285  case AT_AddIndexConstraint:
6286  return "ADD CONSTRAINT";
6287  case AT_AlterConstraint:
6288  return "ALTER CONSTRAINT";
6289  case AT_ValidateConstraint:
6290  return "VALIDATE CONSTRAINT";
6291  case AT_DropConstraint:
6292  return "DROP CONSTRAINT";
6293  case AT_ReAddComment:
6294  return NULL; /* not real grammar */
6295  case AT_AlterColumnType:
6296  return "ALTER COLUMN ... SET DATA TYPE";
6298  return "ALTER COLUMN ... OPTIONS";
6299  case AT_ChangeOwner:
6300  return "OWNER TO";
6301  case AT_ClusterOn:
6302  return "CLUSTER ON";
6303  case AT_DropCluster:
6304  return "SET WITHOUT CLUSTER";
6305  case AT_SetAccessMethod:
6306  return "SET ACCESS METHOD";
6307  case AT_SetLogged:
6308  return "SET LOGGED";
6309  case AT_SetUnLogged:
6310  return "SET UNLOGGED";
6311  case AT_DropOids:
6312  return "SET WITHOUT OIDS";
6313  case AT_SetTableSpace:
6314  return "SET TABLESPACE";
6315  case AT_SetRelOptions:
6316  return "SET";
6317  case AT_ResetRelOptions:
6318  return "RESET";
6319  case AT_ReplaceRelOptions:
6320  return NULL; /* not real grammar */
6321  case AT_EnableTrig:
6322  return "ENABLE TRIGGER";
6323  case AT_EnableAlwaysTrig:
6324  return "ENABLE ALWAYS TRIGGER";
6325  case AT_EnableReplicaTrig:
6326  return "ENABLE REPLICA TRIGGER";
6327  case AT_DisableTrig:
6328  return "DISABLE TRIGGER";
6329  case AT_EnableTrigAll:
6330  return "ENABLE TRIGGER ALL";
6331  case AT_DisableTrigAll:
6332  return "DISABLE TRIGGER ALL";
6333  case AT_EnableTrigUser:
6334  return "ENABLE TRIGGER USER";
6335  case AT_DisableTrigUser:
6336  return "DISABLE TRIGGER USER";
6337  case AT_EnableRule:
6338  return "ENABLE RULE";
6339  case AT_EnableAlwaysRule:
6340  return "ENABLE ALWAYS RULE";
6341  case AT_EnableReplicaRule:
6342  return "ENABLE REPLICA RULE";
6343  case AT_DisableRule:
6344  return "DISABLE RULE";
6345  case AT_AddInherit:
6346  return "INHERIT";
6347  case AT_DropInherit:
6348  return "NO INHERIT";
6349  case AT_AddOf:
6350  return "OF";
6351  case AT_DropOf:
6352  return "NOT OF";
6353  case AT_ReplicaIdentity:
6354  return "REPLICA IDENTITY";
6355  case AT_EnableRowSecurity:
6356  return "ENABLE ROW SECURITY";
6357  case AT_DisableRowSecurity:
6358  return "DISABLE ROW SECURITY";
6359  case AT_ForceRowSecurity:
6360  return "FORCE ROW SECURITY";
6361  case AT_NoForceRowSecurity:
6362  return "NO FORCE ROW SECURITY";
6363  case AT_GenericOptions:
6364  return "OPTIONS";
6365  case AT_AttachPartition:
6366  return "ATTACH PARTITION";
6367  case AT_DetachPartition:
6368  return "DETACH PARTITION";
6370  return "DETACH PARTITION ... FINALIZE";
6371  case AT_AddIdentity:
6372  return "ALTER COLUMN ... ADD IDENTITY";
6373  case AT_SetIdentity:
6374  return "ALTER COLUMN ... SET";
6375  case AT_DropIdentity:
6376  return "ALTER COLUMN ... DROP IDENTITY";
6377  case AT_ReAddStatistics:
6378  return NULL; /* not real grammar */
6379  }
6380 
6381  return NULL;
6382 }
@ AT_AddIndexConstraint
Definition: parsenodes.h:2233
@ AT_DropOf
Definition: parsenodes.h:2264
@ AT_SetOptions
Definition: parsenodes.h:2221
@ AT_DropIdentity
Definition: parsenodes.h:2276
@ AT_SetAttNotNull
Definition: parsenodes.h:2218
@ AT_DisableTrigUser
Definition: parsenodes.h:2256
@ AT_DropNotNull
Definition: parsenodes.h:2216
@ AT_AddOf
Definition: parsenodes.h:2263
@ AT_ResetOptions
Definition: parsenodes.h:2222
@ AT_ReplicaIdentity
Definition: parsenodes.h:2265
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2248
@ AT_EnableRowSecurity
Definition: parsenodes.h:2266
@ AT_AddColumnToView
Definition: parsenodes.h:2213
@ AT_ResetRelOptions
Definition: parsenodes.h:2247
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2251
@ AT_DropOids
Definition: parsenodes.h:2243
@ AT_SetIdentity
Definition: parsenodes.h:2275
@ AT_ReAddStatistics
Definition: parsenodes.h:2277
@ AT_SetUnLogged
Definition: parsenodes.h:2242
@ AT_DisableTrig
Definition: parsenodes.h:2252
@ AT_SetCompression
Definition: parsenodes.h:2224
@ AT_DropExpression
Definition: parsenodes.h:2219
@ AT_AddIndex
Definition: parsenodes.h:2226
@ AT_EnableReplicaRule
Definition: parsenodes.h:2259
@ AT_ReAddIndex
Definition: parsenodes.h:2227
@ AT_DropConstraint
Definition: parsenodes.h:2234
@ AT_SetNotNull
Definition: parsenodes.h:2217
@ AT_ClusterOn
Definition: parsenodes.h:2239
@ AT_AddIdentity
Definition: parsenodes.h:2274
@ AT_ForceRowSecurity
Definition: parsenodes.h:2268
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2258
@ AT_SetAccessMethod
Definition: parsenodes.h:2244
@ AT_AlterColumnType
Definition: parsenodes.h:2236
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2273
@ AT_AddInherit
Definition: parsenodes.h:2261
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2230
@ AT_EnableTrig
Definition: parsenodes.h:2249
@ AT_DropColumn
Definition: parsenodes.h:2225
@ AT_ReAddComment
Definition: parsenodes.h:2235
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2237
@ AT_DisableTrigAll
Definition: parsenodes.h:2254
@ AT_EnableRule
Definition: parsenodes.h:2257
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2269
@ AT_DetachPartition
Definition: parsenodes.h:2272
@ AT_SetStatistics
Definition: parsenodes.h:2220
@ AT_AttachPartition
Definition: parsenodes.h:2271
@ AT_AddConstraint
Definition: parsenodes.h:2228
@ AT_DropInherit
Definition: parsenodes.h:2262
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2250
@ AT_SetLogged
Definition: parsenodes.h:2241
@ AT_SetStorage
Definition: parsenodes.h:2223
@ AT_DisableRule
Definition: parsenodes.h:2260
@ AT_DisableRowSecurity
Definition: parsenodes.h:2267
@ AT_SetRelOptions
Definition: parsenodes.h:2246
@ AT_ChangeOwner
Definition: parsenodes.h:2238
@ AT_EnableTrigUser
Definition: parsenodes.h:2255
@ AT_ReAddConstraint
Definition: parsenodes.h:2229
@ AT_SetTableSpace
Definition: parsenodes.h:2245
@ AT_GenericOptions
Definition: parsenodes.h:2270
@ AT_ColumnDefault
Definition: parsenodes.h:2214
@ AT_CookedColumnDefault
Definition: parsenodes.h:2215
@ AT_AlterConstraint
Definition: parsenodes.h:2231
@ AT_EnableTrigAll
Definition: parsenodes.h:2253
@ AT_DropCluster
Definition: parsenodes.h:2240
@ AT_ValidateConstraint
Definition: parsenodes.h:2232
@ AT_AddColumn
Definition: parsenodes.h:2212

References AT_AddColumn, AT_AddColumnToView, AT_AddConstraint, AT_AddIdentity, AT_AddIndex, AT_AddIndexConstraint, AT_AddInherit, AT_AddOf, AT_AlterColumnGenericOptions, AT_AlterColumnType, AT_AlterConstraint, AT_AttachPartition, AT_ChangeOwner, AT_ClusterOn, AT_ColumnDefault, AT_CookedColumnDefault, AT_DetachPartition, AT_DetachPartitionFinalize, AT_DisableRowSecurity, AT_DisableRule, AT_DisableTrig, AT_DisableTrigAll, AT_DisableTrigUser, AT_DropCluster, AT_DropColumn, AT_DropConstraint, AT_DropExpression, AT_DropIdentity, AT_DropInherit, AT_DropNotNull, AT_DropOf, AT_DropOids, AT_EnableAlwaysRule, AT_EnableAlwaysTrig, AT_EnableReplicaRule, AT_EnableReplicaTrig, AT_EnableRowSecurity, AT_EnableRule, AT_EnableTrig, AT_EnableTrigAll, AT_EnableTrigUser, AT_ForceRowSecurity, AT_GenericOptions, AT_NoForceRowSecurity, AT_ReAddComment, AT_ReAddConstraint, AT_ReAddDomainConstraint, AT_ReAddIndex, AT_ReAddStatistics, AT_ReplaceRelOptions, AT_ReplicaIdentity, AT_ResetOptions, AT_ResetRelOptions, AT_SetAccessMethod, AT_SetAttNotNull, AT_SetCompression, AT_SetIdentity, AT_SetLogged, AT_SetNotNull, AT_SetOptions, AT_SetRelOptions, AT_SetStatistics, AT_SetStorage, AT_SetTableSpace, AT_SetUnLogged, and AT_ValidateConstraint.

Referenced by ATSimplePermissions().

◆ AlterIndexNamespaces()

static void AlterIndexNamespaces ( Relation  classRel,
Relation  rel,
Oid  oldNspOid,
Oid  newNspOid,
ObjectAddresses objsMoved 
)
static

Definition at line 17295 of file tablecmds.c.

17297 {
17298  List *indexList;
17299  ListCell *l;
17300 
17301  indexList = RelationGetIndexList(rel);
17302 
17303  foreach(l, indexList)
17304  {
17305  Oid indexOid = lfirst_oid(l);
17306  ObjectAddress thisobj;
17307 
17308  thisobj.classId = RelationRelationId;
17309  thisobj.objectId = indexOid;
17310  thisobj.objectSubId = 0;
17311 
17312  /*
17313  * Note: currently, the index will not have its own dependency on the
17314  * namespace, so we don't need to do changeDependencyFor(). There's no
17315  * row type in pg_type, either.
17316  *
17317  * XXX this objsMoved test may be pointless -- surely we have a single
17318  * dependency link from a relation to each index?
17319  */
17320  if (!object_address_present(&thisobj, objsMoved))
17321  {
17322  AlterRelationNamespaceInternal(classRel, indexOid,
17323  oldNspOid, newNspOid,
17324  false, objsMoved);
17325  add_exact_object_address(&thisobj, objsMoved);
17326  }
17327  }
17328 
17329  list_free(indexList);
17330 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2641
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2581
void list_free(List *list)
Definition: list.c:1545
#define lfirst_oid(lc)
Definition: pg_list.h:174
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4740
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17225

References add_exact_object_address(), AlterRelationNamespaceInternal(), ObjectAddress::classId, lfirst_oid, list_free(), object_address_present(), ObjectAddress::objectId, ObjectAddress::objectSubId, and RelationGetIndexList().

Referenced by AlterTableNamespaceInternal().

◆ AlterRelationNamespaceInternal()

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

Definition at line 17225 of file tablecmds.c.

17229 {
17230  HeapTuple classTup;
17231  Form_pg_class classForm;
17232  ObjectAddress thisobj;
17233  bool already_done = false;
17234 
17235  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
17236  if (!HeapTupleIsValid(classTup))
17237  elog(ERROR, "cache lookup failed for relation %u", relOid);
17238  classForm = (Form_pg_class) GETSTRUCT(classTup);
17239 
17240  Assert(classForm->relnamespace == oldNspOid);
17241 
17242  thisobj.classId = RelationRelationId;
17243  thisobj.objectId = relOid;
17244  thisobj.objectSubId = 0;
17245 
17246  /*
17247  * If the object has already been moved, don't move it again. If it's
17248  * already in the right place, don't move it, but still fire the object
17249  * access hook.
17250  */
17251  already_done = object_address_present(&thisobj, objsMoved);
17252  if (!already_done && oldNspOid != newNspOid)
17253  {
17254  /* check for duplicate name (more friendly than unique-index failure) */
17255  if (get_relname_relid(NameStr(classForm->relname),
17256  newNspOid) != InvalidOid)
17257  ereport(ERROR,
17258  (errcode(ERRCODE_DUPLICATE_TABLE),
17259  errmsg("relation \"%s\" already exists in schema \"%s\"",
17260  NameStr(classForm->relname),
17261  get_namespace_name(newNspOid))));
17262 
17263  /* classTup is a copy, so OK to scribble on */
17264  classForm->relnamespace = newNspOid;
17265 
17266  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
17267 
17268  /* Update dependency on schema if caller said so */
17269  if (hasDependEntry &&
17270  changeDependencyFor(RelationRelationId,
17271  relOid,
17272  NamespaceRelationId,
17273  oldNspOid,
17274  newNspOid) != 1)
17275  elog(ERROR, "could not change schema dependency for relation \"%s\"",
17276  NameStr(classForm->relname));
17277  }
17278  if (!already_done)
17279  {
17280  add_exact_object_address(&thisobj, objsMoved);
17281 
17282  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
17283  }
17284 
17285  heap_freetuple(classTup);
17286 }
#define NameStr(name)
Definition: c.h:735
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1426
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3348
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1889
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:456
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:182
@ 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().

◆ AlterSeqNamespaces()

static void AlterSeqNamespaces ( Relation  classRel,
Relation  rel,
Oid  oldNspOid,
Oid  newNspOid,
ObjectAddresses objsMoved,
LOCKMODE  lockmode 
)
static

Definition at line 17340 of file tablecmds.c.

17343 {
17344  Relation depRel;
17345  SysScanDesc scan;
17346  ScanKeyData key[2];
17347  HeapTuple tup;
17348 
17349  /*
17350  * SERIAL sequences are those having an auto dependency on one of the
17351  * table's columns (we don't care *which* column, exactly).
17352  */
17353  depRel = table_open(DependRelationId, AccessShareLock);
17354 
17355  ScanKeyInit(&key[0],
17356  Anum_pg_depend_refclassid,
17357  BTEqualStrategyNumber, F_OIDEQ,
17358  ObjectIdGetDatum(RelationRelationId));
17359  ScanKeyInit(&key[1],
17360  Anum_pg_depend_refobjid,
17361  BTEqualStrategyNumber, F_OIDEQ,
17363  /* we leave refobjsubid unspecified */
17364 
17365  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
17366  NULL, 2, key);
17367 
17368  while (HeapTupleIsValid(tup = systable_getnext(scan)))
17369  {
17370  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
17371  Relation seqRel;
17372 
17373  /* skip dependencies other than auto dependencies on columns */
17374  if (depForm->refobjsubid == 0 ||
17375  depForm->classid != RelationRelationId ||
17376  depForm->objsubid != 0 ||
17377  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
17378  continue;
17379 
17380  /* Use relation_open just in case it's an index */
17381  seqRel = relation_open(depForm->objid, lockmode);
17382 
17383  /* skip non-sequence relations */
17384  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
17385  {
17386  /* No need to keep the lock */
17387  relation_close(seqRel, lockmode);
17388  continue;
17389  }
17390 
17391  /* Fix the pg_class and pg_depend entries */
17392  AlterRelationNamespaceInternal(classRel, depForm->objid,
17393  oldNspOid, newNspOid,
17394  true, objsMoved);
17395 
17396  /*
17397  * Sequences used to have entries in pg_type, but no longer do. If we
17398  * ever re-instate that, we'll need to move the pg_type entry to the
17399  * new namespace, too (using AlterTypeNamespaceInternal).
17400  */
17401  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
17402 
17403  /* Now we can close it. Keep the lock till end of transaction. */
17404  relation_close(seqRel, NoLock);
17405  }
17406 
17407  systable_endscan(scan);
17408 
17410 }
@ DEPENDENCY_AUTO
Definition: dependency.h:34
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
#define AccessShareLock
Definition: lockdefs.h:36
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
#define RelationGetForm(relation)
Definition: rel.h:498
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define BTEqualStrategyNumber
Definition: stratnum.h:31

References AccessShareLock, AlterRelationNamespaceInternal(), Assert(), BTEqualStrategyNumber, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, GETSTRUCT, HeapTupleIsValid, InvalidOid, sort-test::key, NoLock, ObjectIdGetDatum(), relation_close(), relation_open(), RelationGetForm, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), and table_open().

Referenced by AlterTableNamespaceInternal().

◆ AlterTable()

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

Definition at line 4270 of file tablecmds.c.

4272 {
4273  Relation rel;
4274 
4275  /* Caller is required to provide an adequate lock. */
4276  rel = relation_open(context->relid, NoLock);
4277 
4278  CheckTableNotInUse(rel, "ALTER TABLE");
4279 
4280  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4281 }
#define stmt
Definition: indent_codes.h:59
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4606

References ATController(), CheckTableNotInUse(), NoLock, relation_open(), AlterTableUtilityContext::relid, and stmt.

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4344 of file tablecmds.c.

4345 {
4346  /*
4347  * This only works if we read catalog tables using MVCC snapshots.
4348  */
4349  ListCell *lcmd;
4351 
4352  foreach(lcmd, cmds)
4353  {
4354  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4355  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4356 
4357  switch (cmd->subtype)
4358  {
4359  /*
4360  * These subcommands rewrite the heap, so require full locks.
4361  */
4362  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4363  * to SELECT */
4364  case AT_SetAccessMethod: /* must rewrite heap */
4365  case AT_SetTableSpace: /* must rewrite heap */
4366  case AT_AlterColumnType: /* must rewrite heap */
4367  cmd_lockmode = AccessExclusiveLock;
4368  break;
4369 
4370  /*
4371  * These subcommands may require addition of toast tables. If
4372  * we add a toast table to a table currently being scanned, we
4373  * might miss data added to the new toast table by concurrent
4374  * insert transactions.
4375  */
4376  case AT_SetStorage: /* may add toast tables, see
4377  * ATRewriteCatalogs() */
4378  cmd_lockmode = AccessExclusiveLock;
4379  break;
4380 
4381  /*
4382  * Removing constraints can affect SELECTs that have been
4383  * optimized assuming the constraint holds true. See also
4384  * CloneFkReferenced.
4385  */
4386  case AT_DropConstraint: /* as DROP INDEX */
4387  case AT_DropNotNull: /* may change some SQL plans */
4388  cmd_lockmode = AccessExclusiveLock;
4389  break;
4390 
4391  /*
4392  * Subcommands that may be visible to concurrent SELECTs
4393  */
4394  case AT_DropColumn: /* change visible to SELECT */
4395  case AT_AddColumnToView: /* CREATE VIEW */
4396  case AT_DropOids: /* used to equiv to DropColumn */
4397  case AT_EnableAlwaysRule: /* may change SELECT rules */
4398  case AT_EnableReplicaRule: /* may change SELECT rules */
4399  case AT_EnableRule: /* may change SELECT rules */
4400  case AT_DisableRule: /* may change SELECT rules */
4401  cmd_lockmode = AccessExclusiveLock;
4402  break;
4403 
4404  /*
4405  * Changing owner may remove implicit SELECT privileges
4406  */
4407  case AT_ChangeOwner: /* change visible to SELECT */
4408  cmd_lockmode = AccessExclusiveLock;
4409  break;
4410 
4411  /*
4412  * Changing foreign table options may affect optimization.
4413  */
4414  case AT_GenericOptions:
4416  cmd_lockmode = AccessExclusiveLock;
4417  break;
4418 
4419  /*
4420  * These subcommands affect write operations only.
4421  */
4422  case AT_EnableTrig:
4423  case AT_EnableAlwaysTrig:
4424  case AT_EnableReplicaTrig:
4425  case AT_EnableTrigAll:
4426  case AT_EnableTrigUser:
4427  case AT_DisableTrig:
4428  case AT_DisableTrigAll:
4429  case AT_DisableTrigUser:
4430  cmd_lockmode = ShareRowExclusiveLock;
4431  break;
4432 
4433  /*
4434  * These subcommands affect write operations only. XXX
4435  * Theoretically, these could be ShareRowExclusiveLock.
4436  */
4437  case AT_ColumnDefault:
4439  case AT_AlterConstraint:
4440  case AT_AddIndex: /* from ADD CONSTRAINT */
4441  case AT_AddIndexConstraint:
4442  case AT_ReplicaIdentity:
4443  case AT_SetNotNull:
4444  case AT_SetAttNotNull:
4445  case AT_EnableRowSecurity:
4446  case AT_DisableRowSecurity:
4447  case AT_ForceRowSecurity:
4448  case AT_NoForceRowSecurity:
4449  case AT_AddIdentity:
4450  case AT_DropIdentity:
4451  case AT_SetIdentity:
4452  case AT_DropExpression:
4453  case AT_SetCompression:
4454  cmd_lockmode = AccessExclusiveLock;
4455  break;
4456 
4457  case AT_AddConstraint:
4458  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4459  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4460  if (IsA(cmd->def, Constraint))
4461  {
4462  Constraint *con = (Constraint *) cmd->def;
4463 
4464  switch (con->contype)
4465  {
4466  case CONSTR_EXCLUSION:
4467  case CONSTR_PRIMARY:
4468  case CONSTR_UNIQUE:
4469 
4470  /*
4471  * Cases essentially the same as CREATE INDEX. We
4472  * could reduce the lock strength to ShareLock if
4473  * we can work out how to allow concurrent catalog
4474  * updates. XXX Might be set down to
4475  * ShareRowExclusiveLock but requires further
4476  * analysis.
4477  */
4478  cmd_lockmode = AccessExclusiveLock;
4479  break;
4480  case CONSTR_FOREIGN:
4481 
4482  /*
4483  * We add triggers to both tables when we add a
4484  * Foreign Key, so the lock level must be at least
4485  * as strong as CREATE TRIGGER.
4486  */
4487  cmd_lockmode = ShareRowExclusiveLock;
4488  break;
4489 
4490  default:
4491  cmd_lockmode = AccessExclusiveLock;
4492  }
4493  }
4494  break;
4495 
4496  /*
4497  * These subcommands affect inheritance behaviour. Queries
4498  * started before us will continue to see the old inheritance
4499  * behaviour, while queries started after we commit will see
4500  * new behaviour. No need to prevent reads or writes to the
4501  * subtable while we hook it up though. Changing the TupDesc
4502  * may be a problem, so keep highest lock.
4503  */
4504  case AT_AddInherit:
4505  case AT_DropInherit:
4506  cmd_lockmode = AccessExclusiveLock;
4507  break;
4508 
4509  /*
4510  * These subcommands affect implicit row type conversion. They
4511  * have affects similar to CREATE/DROP CAST on queries. don't
4512  * provide for invalidating parse trees as a result of such
4513  * changes, so we keep these at AccessExclusiveLock.
4514  */
4515  case AT_AddOf:
4516  case AT_DropOf:
4517  cmd_lockmode = AccessExclusiveLock;
4518  break;
4519 
4520  /*
4521  * Only used by CREATE OR REPLACE VIEW which must conflict
4522  * with an SELECTs currently using the view.
4523  */
4524  case AT_ReplaceRelOptions:
4525  cmd_lockmode = AccessExclusiveLock;
4526  break;
4527 
4528  /*
4529  * These subcommands affect general strategies for performance
4530  * and maintenance, though don't change the semantic results
4531  * from normal data reads and writes. Delaying an ALTER TABLE
4532  * behind currently active writes only delays the point where
4533  * the new strategy begins to take effect, so there is no
4534  * benefit in waiting. In this case the minimum restriction
4535  * applies: we don't currently allow concurrent catalog
4536  * updates.
4537  */
4538  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4539  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4540  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4541  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4542  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4543  cmd_lockmode = ShareUpdateExclusiveLock;
4544  break;
4545 
4546  case AT_SetLogged:
4547  case AT_SetUnLogged:
4548  cmd_lockmode = AccessExclusiveLock;
4549  break;
4550 
4551  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4552  cmd_lockmode = ShareUpdateExclusiveLock;
4553  break;
4554 
4555  /*
4556  * Rel options are more complex than first appears. Options
4557  * are set here for tables, views and indexes; for historical
4558  * reasons these can all be used with ALTER TABLE, so we can't
4559  * decide between them using the basic grammar.
4560  */
4561  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4562  * getTables() */
4563  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4564  * getTables() */
4565  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4566  break;
4567 
4568  case AT_AttachPartition:
4569  cmd_lockmode = ShareUpdateExclusiveLock;
4570  break;
4571 
4572  case AT_DetachPartition:
4573  if (((PartitionCmd *) cmd->def)->concurrent)
4574  cmd_lockmode = ShareUpdateExclusiveLock;
4575  else
4576  cmd_lockmode = AccessExclusiveLock;
4577  break;
4578 
4580  cmd_lockmode = ShareUpdateExclusiveLock;
4581  break;
4582 
4583  default: /* oops */
4584  elog(ERROR, "unrecognized alter table type: %d",
4585  (int) cmd->subtype);
4586  break;
4587  }
4588 
4589  /*
4590  * Take the greatest lockmode from any subcommand
4591  */
4592  if (cmd_lockmode > lockmode)
4593  lockmode = cmd_lockmode;
4594  }
4595 
4596  return lockmode;
4597 }
int LOCKMODE
Definition: lockdefs.h:26
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
@ CONSTR_UNIQUE
Definition: parsenodes.h:2569
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2570
@ CONSTR_PRIMARY
Definition: parsenodes.h:2568
#define lfirst(lc)
Definition: pg_list.h:172
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2110
AlterTableType subtype
Definition: parsenodes.h:2290
ConstrType contype
Definition: parsenodes.h:2595

References AccessExclusiveLock, AlterTableGetRelOptionsLockLevel(), AT_AddColumn, AT_AddColumnToView, AT_AddConstraint, AT_AddIdentity, AT_AddIndex, AT_AddIndexConstraint, AT_AddInherit, AT_AddOf, AT_AlterColumnGenericOptions, AT_AlterColumnType, AT_AlterConstraint, AT_AttachPartition, AT_ChangeOwner, AT_ClusterOn, AT_ColumnDefault, AT_CookedColumnDefault, AT_DetachPartition, AT_DetachPartitionFinalize, AT_DisableRowSecurity, AT_DisableRule, AT_DisableTrig, AT_DisableTrigAll, AT_DisableTrigUser, AT_DropCluster, AT_DropColumn, AT_DropConstraint, AT_DropExpression, AT_DropIdentity, AT_DropInherit, AT_DropNotNull, AT_DropOf, AT_DropOids, AT_EnableAlwaysRule, AT_EnableAlwaysTrig, AT_EnableReplicaRule, AT_EnableReplicaTrig, AT_EnableRowSecurity, AT_EnableRule, AT_EnableTrig, AT_EnableTrigAll, AT_EnableTrigUser, AT_ForceRowSecurity, AT_GenericOptions, AT_NoForceRowSecurity, AT_ReAddConstraint, AT_ReAddDomainConstraint, AT_ReplaceRelOptions, AT_ReplicaIdentity, AT_ResetOptions, AT_ResetRelOptions, AT_SetAccessMethod, AT_SetAttNotNull, 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 4299 of file tablecmds.c.

4300 {
4301  Relation rel;
4302  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4303 
4304  rel = relation_open(relid, lockmode);
4305 
4307 
4308  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4309 }
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4344

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4211 of file tablecmds.c.

4212 {
4213  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4214  stmt->missing_ok ? RVR_MISSING_OK : 0,
4216  (void *) stmt);
4217 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:221
@ RVR_MISSING_OK
Definition: namespace.h:71
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:17738

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

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 15153 of file tablecmds.c.

15154 {
15155  List *relations = NIL;
15156  ListCell *l;
15157  ScanKeyData key[1];
15158  Relation rel;
15159  TableScanDesc scan;
15160  HeapTuple tuple;
15161  Oid orig_tablespaceoid;
15162  Oid new_tablespaceoid;
15163  List *role_oids = roleSpecsToIds(stmt->roles);
15164 
15165  /* Ensure we were not asked to move something we can't */
15166  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
15167  stmt->objtype != OBJECT_MATVIEW)
15168  ereport(ERROR,
15169  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15170  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
15171 
15172  /* Get the orig and new tablespace OIDs */
15173  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
15174  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
15175 
15176  /* Can't move shared relations in to or out of pg_global */
15177  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
15178  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
15179  new_tablespaceoid == GLOBALTABLESPACE_OID)
15180  ereport(ERROR,
15181  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15182  errmsg("cannot move relations in to or out of pg_global tablespace")));
15183 
15184  /*
15185  * Must have CREATE rights on the new tablespace, unless it is the
15186  * database default tablespace (which all users implicitly have CREATE
15187  * rights on).
15188  */
15189  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
15190  {
15191  AclResult aclresult;
15192 
15193  aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
15194  ACL_CREATE);
15195  if (aclresult != ACLCHECK_OK)
15196  aclcheck_error(aclresult, OBJECT_TABLESPACE,
15197  get_tablespace_name(new_tablespaceoid));
15198  }
15199 
15200  /*
15201  * Now that the checks are done, check if we should set either to
15202  * InvalidOid because it is our database's default tablespace.
15203  */
15204  if (orig_tablespaceoid == MyDatabaseTableSpace)
15205  orig_tablespaceoid = InvalidOid;
15206 
15207  if (new_tablespaceoid == MyDatabaseTableSpace)
15208  new_tablespaceoid = InvalidOid;
15209 
15210  /* no-op */
15211  if (orig_tablespaceoid == new_tablespaceoid)
15212  return new_tablespaceoid;
15213 
15214  /*
15215  * Walk the list of objects in the tablespace and move them. This will
15216  * only find objects in our database, of course.
15217  */
15218  ScanKeyInit(&key[0],
15219  Anum_pg_class_reltablespace,
15220  BTEqualStrategyNumber, F_OIDEQ,
15221  ObjectIdGetDatum(orig_tablespaceoid));
15222 
15223  rel = table_open(RelationRelationId, AccessShareLock);
15224  scan = table_beginscan_catalog(rel, 1, key);
15225  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
15226  {
15227  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
15228  Oid relOid = relForm->oid;
15229 
15230  /*
15231  * Do not move objects in pg_catalog as part of this, if an admin
15232  * really wishes to do so, they can issue the individual ALTER
15233  * commands directly.
15234  *
15235  * Also, explicitly avoid any shared tables, temp tables, or TOAST
15236  * (TOAST will be moved with the main table).
15237  */
15238  if (IsCatalogNamespace(relForm->relnamespace) ||
15239  relForm->relisshared ||
15240  isAnyTempNamespace(relForm->relnamespace) ||
15241  IsToastNamespace(relForm->relnamespace))
15242  continue;
15243 
15244  /* Only move the object type requested */
15245  if ((stmt->objtype == OBJECT_TABLE &&
15246  relForm->relkind != RELKIND_RELATION &&
15247  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
15248  (stmt->objtype == OBJECT_INDEX &&
15249  relForm->relkind != RELKIND_INDEX &&
15250  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
15251  (stmt->objtype == OBJECT_MATVIEW &&
15252  relForm->relkind != RELKIND_MATVIEW))
15253  continue;
15254 
15255  /* Check if we are only moving objects owned by certain roles */
15256  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
15257  continue;
15258 
15259  /*
15260  * Handle permissions-checking here since we are locking the tables
15261  * and also to avoid doing a bunch of work only to fail part-way. Note
15262  * that permissions will also be checked by AlterTableInternal().
15263  *
15264  * Caller must be considered an owner on the table to move it.
15265  */
15266  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
15268  NameStr(relForm->relname));
15269 
15270  if (stmt->nowait &&
15272  ereport(ERROR,
15273  (errcode(ERRCODE_OBJECT_IN_USE),
15274  errmsg("aborting because lock on relation \"%s.%s\" is not available",
15275  get_namespace_name(relForm->relnamespace),
15276  NameStr(relForm->relname))));
15277  else
15279 
15280  /* Add to our list of objects to move */
15281  relations = lappend_oid(relations, relOid);
15282  }
15283 
15284  table_endscan(scan);
15286 
15287  if (relations == NIL)
15288  ereport(NOTICE,
15289  (errcode(ERRCODE_NO_DATA_FOUND),
15290  errmsg("no matching relations in tablespace \"%s\" found",
15291  orig_tablespaceoid == InvalidOid ? "(database default)" :
15292  get_tablespace_name(orig_tablespaceoid))));
15293 
15294  /* Everything is locked, loop through and move all of the relations. */
15295  foreach(l, relations)
15296  {
15297  List *cmds = NIL;
15299 
15300  cmd->subtype = AT_SetTableSpace;
15301  cmd->name = stmt->new_tablespacename;
15302 
15303  cmds = lappend(cmds, cmd);
15304 
15306  /* OID is set by AlterTableInternal */
15307  AlterTableInternal(lfirst_oid(l), cmds, false);
15309  }
15310 
15311  return new_tablespaceoid;
15312 }
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
@ ACLCHECK_NOT_OWNER
Definition: acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2669
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3760
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:3961
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1478
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1432
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1659
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:202
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:184
#define NOTICE
Definition: elog.h:35
void EventTriggerAlterTableStart(Node *parsetree)
void EventTriggerAlterTableEnd(void)
Oid MyDatabaseTableSpace
Definition: globals.c:91
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1086
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:2007
Oid GetUserId(void)
Definition: miscinit.c:509
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3220
#define makeNode(_type_)
Definition: nodes.h:176
ObjectType get_relkind_objtype(char relkind)
@ OBJECT_MATVIEW
Definition: parsenodes.h:2143
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2162
@ OBJECT_INDEX
Definition: parsenodes.h:2140
@ OBJECT_TABLE
Definition: parsenodes.h:2161
#define ACL_CREATE
Definition: parsenodes.h:92
@ ForwardScanDirection
Definition: sdir.h:28
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:1009
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4299

References AccessExclusiveLock, AccessShareLock, ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTableInternal(), AT_SetTableSpace, BTEqualStrategyNumber, ConditionalLockRelationOid(), ereport, errcode(), errmsg(), ERROR, EventTriggerAlterTableEnd(), EventTriggerAlterTableStart(), ForwardScanDirection, get_namespace_name(), get_rel_relkind(), get_relkind_objtype(), get_tablespace_name(), get_tablespace_oid(), GETSTRUCT, GetUserId(), heap_getnext(), InvalidOid, isAnyTempNamespace(), IsCatalogNamespace(), IsToastNamespace(), sort-test::key, lappend(), lappend_oid(), lfirst_oid, list_member_oid(), LockRelationOid(), makeNode, MyDatabaseTableSpace, AlterTableCmd::name, NameStr, NIL, NOTICE, object_aclcheck(), OBJECT_INDEX, OBJECT_MATVIEW, object_ownercheck(), OBJECT_TABLE, OBJECT_TABLESPACE, ObjectIdGetDatum(), OidIsValid, roleSpecsToIds(), ScanKeyInit(), stmt, AlterTableCmd::subtype, table_beginscan_catalog(), table_close(), table_endscan(), and table_open().

Referenced by ProcessUtilitySlow().

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 17115 of file tablecmds.c.

17116 {
17117  Relation rel;
17118  Oid relid;
17119  Oid oldNspOid;
17120  Oid nspOid;
17121  RangeVar *newrv;
17122  ObjectAddresses *objsMoved;
17123  ObjectAddress myself;
17124 
17126  stmt->missing_ok ? RVR_MISSING_OK : 0,
17128  (void *) stmt);
17129 
17130  if (!OidIsValid(relid))
17131  {
17132  ereport(NOTICE,
17133  (errmsg("relation \"%s\" does not exist, skipping",
17134  stmt->relation->relname)));
17135  return InvalidObjectAddress;
17136  }
17137 
17138  rel = relation_open(relid, NoLock);
17139 
17140  oldNspOid = RelationGetNamespace(rel);
17141 
17142  /* If it's an owned sequence, disallow moving it by itself. */
17143  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
17144  {
17145  Oid tableId;
17146  int32 colId;
17147 
17148  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
17149  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
17150  ereport(ERROR,
17151  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17152  errmsg("cannot move an owned sequence into another schema"),
17153  errdetail("Sequence \"%s\" is linked to table \"%s\".",
17155  get_rel_name(tableId))));
17156  }
17157 
17158  /* Get and lock schema OID and check its permissions. */
17159  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
17160  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
17161 
17162  /* common checks on switching namespaces */
17163  CheckSetNamespace(oldNspOid, nspOid);
17164 
17165  objsMoved = new_object_addresses();
17166  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
17167  free_object_addresses(objsMoved);
17168 
17169  ObjectAddressSet(myself, RelationRelationId, relid);
17170 
17171  if (oldschema)
17172  *oldschema = oldNspOid;
17173 
17174  /* close rel, but keep lock until commit */
17175  relation_close(rel, NoLock);
17176 
17177  return myself;
17178 }
signed int int32
Definition: c.h:483
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2532
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2821
int errdetail(const char *fmt,...)
Definition: elog.c:1202
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1932
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:425
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:519
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2992
const ObjectAddress InvalidObjectAddress
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:827
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17186

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

Referenced by ExecAlterObjectSchemaStmt().

◆ AlterTableNamespaceInternal()

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

Definition at line 17186 of file tablecmds.c.

17188 {
17189  Relation classRel;
17190 
17191  Assert(objsMoved != NULL);
17192 
17193  /* OK, modify the pg_class row and pg_depend entry */
17194  classRel = table_open(RelationRelationId, RowExclusiveLock);
17195 
17196  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
17197  nspOid, true, objsMoved);
17198 
17199  /* Fix the table's row type too, if it has one */
17200  if (OidIsValid(rel->rd_rel->reltype))
17201  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
17202  nspOid, false, false, objsMoved);
17203 
17204  /* Fix other dependent stuff */
17205  if (rel->rd_rel->relkind == RELKIND_RELATION ||
17206  rel->rd_rel->relkind == RELKIND_MATVIEW ||
17207  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
17208  {
17209  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
17210  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
17211  objsMoved, AccessExclusiveLock);
17212  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
17213  false, objsMoved);
17214  }
17215 
17216  table_close(classRel, RowExclusiveLock);
17217 }
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
Definition: tablecmds.c:17340
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17295
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3946

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

◆ ATAddCheckNNConstraint()

static ObjectAddress ATAddCheckNNConstraint ( List **  wqueue,
AlteredTableInfo tab,
Relation  rel,
Constraint constr,
bool  recurse,
bool  recursing,
bool  is_readd,
LOCKMODE  lockmode 
)
static

Definition at line 9249 of file tablecmds.c.

9252 {
9253  List *newcons;
9254  ListCell *lcon;
9255  List *children;
9256  ListCell *child;
9258 
9259  /* At top level, permission check was done in ATPrepCmd, else do it */
9260  if (recursing)
9262 
9263  /*
9264  * Call AddRelationNewConstraints to do the work, making sure it works on
9265  * a copy of the Constraint so transformExpr can't modify the original. It
9266  * returns a list of cooked constraints.
9267  *
9268  * If the constraint ends up getting merged with a pre-existing one, it's
9269  * omitted from the returned list, which is what we want: we do not need
9270  * to do any validation work. That can only happen at child tables,
9271  * though, since we disallow merging at the top level.
9272  */
9273  newcons = AddRelationNewConstraints(rel, NIL,
9274  list_make1(copyObject(constr)),
9275  recursing || is_readd, /* allow_merge */
9276  !recursing, /* is_local */
9277  is_readd, /* is_internal */
9278  NULL); /* queryString not available
9279  * here */
9280 
9281  /* we don't expect more than one constraint here */
9282  Assert(list_length(newcons) <= 1);
9283 
9284  /* Add each to-be-validated constraint to Phase 3's queue */
9285  foreach(lcon, newcons)
9286  {
9287  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
9288 
9289  if (!ccon->skip_validation && ccon->contype != CONSTR_NOTNULL)
9290  {
9291  NewConstraint *newcon;
9292 
9293  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9294  newcon->name = ccon->name;
9295  newcon->contype = ccon->contype;
9296  newcon->qual = ccon->expr;
9297 
9298  tab->constraints = lappend(tab->constraints, newcon);
9299  }
9300 
9301  /* Save the actually assigned name if it was defaulted */
9302  if (constr->conname == NULL)
9303  constr->conname = ccon->name;
9304 
9305  /*
9306  * If adding a not-null constraint, set the pg_attribute flag and tell
9307  * phase 3 to verify existing rows, if needed.
9308  */
9309  if (constr->contype == CONSTR_NOTNULL)
9310  set_attnotnull(wqueue, rel, ccon->attnum,
9311  !ccon->is_no_inherit, lockmode);
9312 
9313  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
9314  }
9315 
9316  /* At this point we must have a locked-down name to use */
9317  Assert(newcons == NIL || constr->conname != NULL);
9318 
9319  /* Advance command counter in case same table is visited multiple times */
9321 
9322  /*
9323  * If the constraint got merged with an existing constraint, we're done.
9324  * We mustn't recurse to child tables in this case, because they've
9325  * already got the constraint, and visiting them again would lead to an
9326  * incorrect value for coninhcount.
9327  */
9328  if (newcons == NIL)
9329  return address;
9330 
9331  /*
9332  * If adding a NO INHERIT constraint, no need to find our children.
9333  */
9334  if (constr->is_no_inherit)
9335  return address;
9336 
9337  /*
9338  * Propagate to children as appropriate. Unlike most other ALTER
9339  * routines, we have to do this one level of recursion at a time; we can't
9340  * use find_all_inheritors to do it in one pass.
9341  */
9342  children =
9344 
9345  /*
9346  * Check if ONLY was specified with ALTER TABLE. If so, allow the
9347  * constraint creation only if there are no children currently. Error out
9348  * otherwise.
9349  */
9350  if (!recurse && children != NIL)
9351  ereport(ERROR,
9352  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9353  errmsg("constraint must be added to child tables too")));
9354 
9355  /*
9356  * The constraint must appear as inherited in children, so create a
9357  * modified constraint object to use.
9358  */
9359  constr = copyObject(constr);
9360  constr->inhcount = 1;
9361  foreach(child, children)
9362  {
9363  Oid childrelid = lfirst_oid(child);
9364  Relation childrel;
9365  AlteredTableInfo *childtab;
9366 
9367  /* find_inheritance_children already got lock */
9368  childrel = table_open(childrelid, NoLock);
9369  CheckTableNotInUse(childrel, "ALTER TABLE");
9370 
9371  /* Find or create work queue entry for this table */
9372  childtab = ATGetQueueEntry(wqueue, childrel);
9373 
9374  /*
9375  * Recurse to child. XXX if we didn't create a constraint on the
9376  * parent because it already existed, and we do create one on a child,
9377  * should we return that child's constraint ObjectAddress here?
9378  */
9379  ATAddCheckNNConstraint(wqueue, childtab, childrel,
9380  constr, recurse, true, is_readd, lockmode);
9381 
9382  table_close(childrel, NoLock);
9383  }
9384 
9385  return address;
9386 }
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2290
@ CONSTR_NOTNULL
Definition: parsenodes.h:2563
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:59
static int list_length(const List *l)
Definition: pg_list.h:152
#define list_make1(x1)
Definition: pg_list.h:212
bool is_no_inherit
Definition: parsenodes.h:2604
Oid conoid
Definition: heap.h:39
char * name
Definition: heap.h:40
AttrNumber attnum
Definition: heap.h:41
bool skip_validation
Definition: heap.h:43
bool is_no_inherit
Definition: heap.h:46
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:42
#define ATT_TABLE
Definition: tablecmds.c:317
static ObjectAddress ATAddCheckNNConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:9249
static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
Definition: tablecmds.c:6392
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:322
static bool set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:7527

References AddRelationNewConstraints(), Assert(), AT_AddConstraint, ATGetQueueEntry(), ATSimplePermissions(), ATT_FOREIGN_TABLE, ATT_TABLE, CookedConstraint::attnum, CheckTableNotInUse(), CommandCounterIncrement(), Constraint::conname, CookedConstraint::conoid, CONSTR_NOTNULL, AlteredTableInfo::constraints, NewConstraint::contype, CookedConstraint::contype, Constraint::contype, copyObject, ereport, errcode(), errmsg(), ERROR, CookedConstraint::expr, find_inheritance_children(), Constraint::inhcount, InvalidObjectAddress, CookedConstraint::is_no_inherit, Constraint::is_no_inherit, lappend(), lfirst, lfirst_oid, list_length(), list_make1, NewConstraint::name, CookedConstraint::name, NIL, NoLock, ObjectAddressSet, palloc0(), NewConstraint::qual, RelationGetRelid, set_attnotnull(), CookedConstraint::skip_validation, table_close(), and table_open().

Referenced by ATExecAddConstraint(), and DetachAddConstraintIfNeeded().

◆ ATAddForeignKeyConstraint()

static ObjectAddress ATAddForeignKeyConstraint ( List **  wqueue,
AlteredTableInfo tab,
Relation  rel,
Constraint fkconstraint,
bool  recurse,
bool  recursing,
LOCKMODE  lockmode 
)
static

Definition at line 9404 of file tablecmds.c.

9407 {
9408  Relation pkrel;
9409  int16 pkattnum[INDEX_MAX_KEYS] = {0};
9410  int16 fkattnum[INDEX_MAX_KEYS] = {0};
9411  Oid pktypoid[INDEX_MAX_KEYS] = {0};
9412  Oid fktypoid[INDEX_MAX_KEYS] = {0};
9413  Oid opclasses[INDEX_MAX_KEYS] = {0};
9414  Oid pfeqoperators[INDEX_MAX_KEYS] = {0};
9415  Oid ppeqoperators[INDEX_MAX_KEYS] = {0};
9416  Oid ffeqoperators[INDEX_MAX_KEYS] = {0};
9417  int16 fkdelsetcols[INDEX_MAX_KEYS] = {0};
9418  int i;
9419  int numfks,
9420  numpks,
9421  numfkdelsetcols;
9422  Oid indexOid;
9423  bool old_check_ok;
9424  ObjectAddress address;
9425  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
9426 
9427  /*
9428  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
9429  * delete rows out from under us.
9430  */
9431  if (OidIsValid(fkconstraint->old_pktable_oid))
9432  pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
9433  else
9434  pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
9435 
9436  /*
9437  * Validity checks (permission checks wait till we have the column
9438  * numbers)
9439  */
9440  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9441  {
9442  if (!recurse)
9443  ereport(ERROR,
9444  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9445  errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9447  RelationGetRelationName(pkrel))));
9448  if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
9449  ereport(ERROR,
9450  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9451  errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9453  RelationGetRelationName(pkrel)),
9454  errdetail("This feature is not yet supported on partitioned tables.")));
9455  }
9456 
9457  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9458  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9459  ereport(ERROR,
9460  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9461  errmsg("referenced relation \"%s\" is not a table",
9462  RelationGetRelationName(pkrel))));
9463 
9464  if (!allowSystemTableMods && IsSystemRelation(pkrel))
9465  ereport(ERROR,
9466  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
9467  errmsg("permission denied: \"%s\" is a system catalog",
9468  RelationGetRelationName(pkrel))));
9469 
9470  /*
9471  * References from permanent or unlogged tables to temp tables, and from
9472  * permanent tables to unlogged tables, are disallowed because the
9473  * referenced data can vanish out from under us. References from temp
9474  * tables to any other table type are also disallowed, because other
9475  * backends might need to run the RI triggers on the perm table, but they
9476  * can't reliably see tuples in the local buffers of other backends.
9477  */
9478  switch (rel->rd_rel->relpersistence)
9479  {
9480  case RELPERSISTENCE_PERMANENT:
9481  if (!RelationIsPermanent(pkrel))
9482  ereport(ERROR,
9483  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9484  errmsg("constraints on permanent tables may reference only permanent tables")));
9485  break;
9486  case RELPERSISTENCE_UNLOGGED:
9487  if (!RelationIsPermanent(pkrel)
9488  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
9489  ereport(ERROR,
9490  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9491  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
9492  break;
9493  case RELPERSISTENCE_TEMP:
9494  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
9495  ereport(ERROR,
9496  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9497  errmsg("constraints on temporary tables may reference only temporary tables")));
9498  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
9499  ereport(ERROR,
9500  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9501  errmsg("constraints on temporary tables must involve temporary tables of this session")));
9502  break;
9503  }
9504 
9505  /*
9506  * Look up the referencing attributes to make sure they exist, and record
9507  * their attnums and type OIDs.
9508  */
9510  fkconstraint->fk_attrs,
9511  fkattnum, fktypoid);
9512 
9513  numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel),
9514  fkconstraint->fk_del_set_cols,
9515  fkdelsetcols, NULL);
9516  validateFkOnDeleteSetColumns(numfks, fkattnum,
9517  numfkdelsetcols, fkdelsetcols,
9518  fkconstraint->fk_del_set_cols);
9519 
9520  /*
9521  * If the attribute list for the referenced table was omitted, lookup the
9522  * definition of the primary key and use it. Otherwise, validate the
9523  * supplied attribute list. In either case, discover the index OID and
9524  * index opclasses, and the attnums and type OIDs of the attributes.
9525  */
9526  if (fkconstraint->pk_attrs == NIL)
9527  {
9528  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
9529  &fkconstraint->pk_attrs,
9530  pkattnum, pktypoid,
9531  opclasses);
9532  }
9533  else
9534  {
9535  numpks = transformColumnNameList(RelationGetRelid(pkrel),
9536  fkconstraint->pk_attrs,
9537  pkattnum, pktypoid);
9538  /* Look for an index matching the column list */
9539  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
9540  opclasses);
9541  }
9542 
9543  /*
9544  * Now we can check permissions.
9545  */
9546  checkFkeyPermissions(pkrel, pkattnum, numpks);
9547 
9548  /*
9549  * Check some things for generated columns.
9550  */
9551  for (i = 0; i < numfks; i++)
9552  {
9553  char attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
9554 
9555  if (attgenerated)
9556  {
9557  /*
9558  * Check restrictions on UPDATE/DELETE actions, per SQL standard
9559  */
9560  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
9561  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
9562  fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
9563  ereport(ERROR,
9564  (errcode(ERRCODE_SYNTAX_ERROR),
9565  errmsg("invalid %s action for foreign key constraint containing generated column",
9566  "ON UPDATE")));
9567  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
9568  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
9569  ereport(ERROR,
9570  (errcode(ERRCODE_SYNTAX_ERROR),
9571  errmsg("invalid %s action for foreign key constraint containing generated column",
9572  "ON DELETE")));
9573  }
9574  }
9575 
9576  /*
9577  * Look up the equality operators to use in the constraint.
9578  *
9579  * Note that we have to be careful about the difference between the actual
9580  * PK column type and the opclass' declared input type, which might be
9581  * only binary-compatible with it. The declared opcintype is the right
9582  * thing to probe pg_amop with.
9583  */
9584  if (numfks != numpks)
9585  ereport(ERROR,
9586  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
9587  errmsg("number of referencing and referenced columns for foreign key disagree")));
9588 
9589  /*
9590  * On the strength of a previous constraint, we might avoid scanning
9591  * tables to validate this one. See below.
9592  */
9593  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
9594  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
9595 
9596  for (i = 0; i < numpks; i++)
9597  {
9598  Oid pktype = pktypoid[i];
9599  Oid fktype = fktypoid[i];
9600  Oid fktyped;
9601  HeapTuple cla_ht;
9602  Form_pg_opclass cla_tup;
9603  Oid amid;
9604  Oid opfamily;
9605  Oid opcintype;
9606  Oid pfeqop;
9607  Oid ppeqop;
9608  Oid ffeqop;
9609  int16 eqstrategy;
9610  Oid pfeqop_right;
9611 
9612  /* We need several fields out of the pg_opclass entry */
9613  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
9614  if (!HeapTupleIsValid(cla_ht))
9615  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
9616  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
9617  amid = cla_tup->opcmethod;
9618  opfamily = cla_tup->opcfamily;
9619  opcintype = cla_tup->opcintype;
9620  ReleaseSysCache(cla_ht);
9621 
9622  /*
9623  * Check it's a btree; currently this can never fail since no other
9624  * index AMs support unique indexes. If we ever did have other types
9625  * of unique indexes, we'd need a way to determine which operator
9626  * strategy number is equality. (Is it reasonable to insist that
9627  * every such index AM use btree's number for equality?)
9628  */
9629  if (amid != BTREE_AM_OID)
9630  elog(ERROR, "only b-tree indexes are supported for foreign keys");
9631  eqstrategy = BTEqualStrategyNumber;
9632 
9633  /*
9634  * There had better be a primary equality operator for the index.
9635  * We'll use it for PK = PK comparisons.
9636  */
9637  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
9638  eqstrategy);
9639 
9640  if (!OidIsValid(ppeqop))
9641  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
9642  eqstrategy, opcintype, opcintype, opfamily);
9643 
9644  /*
9645  * Are there equality operators that take exactly the FK type? Assume
9646  * we should look through any domain here.
9647  */
9648  fktyped = getBaseType(fktype);
9649 
9650  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
9651  eqstrategy);
9652  if (OidIsValid(pfeqop))
9653  {
9654  pfeqop_right = fktyped;
9655  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
9656  eqstrategy);
9657  }
9658  else
9659  {
9660  /* keep compiler quiet */
9661  pfeqop_right = InvalidOid;
9662  ffeqop = InvalidOid;
9663  }
9664 
9665  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9666  {
9667  /*
9668  * Otherwise, look for an implicit cast from the FK type to the
9669  * opcintype, and if found, use the primary equality operator.
9670  * This is a bit tricky because opcintype might be a polymorphic
9671  * type such as ANYARRAY or ANYENUM; so what we have to test is
9672  * whether the two actual column types can be concurrently cast to
9673  * that type. (Otherwise, we'd fail to reject combinations such
9674  * as int[] and point[].)
9675  */
9676  Oid input_typeids[2];
9677  Oid target_typeids[2];
9678 
9679  input_typeids[0] = pktype;
9680  input_typeids[1] = fktype;
9681  target_typeids[0] = opcintype;
9682  target_typeids[1] = opcintype;
9683  if (can_coerce_type(2, input_typeids, target_typeids,
9685  {
9686  pfeqop = ffeqop = ppeqop;
9687  pfeqop_right = opcintype;
9688  }
9689  }
9690 
9691  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9692  ereport(ERROR,
9693  (errcode(ERRCODE_DATATYPE_MISMATCH),
9694  errmsg("foreign key constraint \"%s\" cannot be implemented",
9695  fkconstraint->conname),
9696  errdetail("Key columns \"%s\" and \"%s\" "
9697  "are of incompatible types: %s and %s.",
9698  strVal(list_nth(fkconstraint->fk_attrs, i)),
9699  strVal(list_nth(fkconstraint->pk_attrs, i)),
9700  format_type_be(fktype),
9701  format_type_be(pktype))));
9702 
9703  if (old_check_ok)
9704  {
9705  /*
9706  * When a pfeqop changes, revalidate the constraint. We could
9707  * permit intra-opfamily changes, but that adds subtle complexity
9708  * without any concrete benefit for core types. We need not
9709  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
9710  */
9711  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
9712  old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
9713  old_pfeqop_item);
9714  }
9715  if (old_check_ok)
9716  {
9717  Oid old_fktype;
9718  Oid new_fktype;
9719  CoercionPathType old_pathtype;
9720  CoercionPathType new_pathtype;
9721  Oid old_castfunc;
9722  Oid new_castfunc;
9724  fkattnum[i] - 1);
9725 
9726  /*
9727  * Identify coercion pathways from each of the old and new FK-side
9728  * column types to the right (foreign) operand type of the pfeqop.
9729  * We may assume that pg_constraint.conkey is not changing.
9730  */
9731  old_fktype = attr->atttypid;
9732  new_fktype = fktype;
9733  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
9734  &old_castfunc);
9735  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
9736  &new_castfunc);
9737 
9738  /*
9739  * Upon a change to the cast from the FK column to its pfeqop
9740  * operand, revalidate the constraint. For this evaluation, a
9741  * binary coercion cast is equivalent to no cast at all. While
9742  * type implementors should design implicit casts with an eye
9743  * toward consistency of operations like equality, we cannot
9744  * assume here that they have done so.
9745  *
9746  * A function with a polymorphic argument could change behavior
9747  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
9748  * when the cast destination is polymorphic, we only avoid
9749  * revalidation if the input type has not changed at all. Given
9750  * just the core data types and operator classes, this requirement
9751  * prevents no would-be optimizations.
9752  *
9753  * If the cast converts from a base type to a domain thereon, then
9754  * that domain type must be the opcintype of the unique index.
9755  * Necessarily, the primary key column must then be of the domain
9756  * type. Since the constraint was previously valid, all values on
9757  * the foreign side necessarily exist on the primary side and in
9758  * turn conform to the domain. Consequently, we need not treat
9759  * domains specially here.
9760  *
9761  * Since we require that all collations share the same notion of
9762  * equality (which they do, because texteq reduces to bitwise
9763  * equality), we don't compare collation here.
9764  *
9765  * We need not directly consider the PK type. It's necessarily
9766  * binary coercible to the opcintype of the unique index column,
9767  * and ri_triggers.c will only deal with PK datums in terms of
9768  * that opcintype. Changing the opcintype also changes pfeqop.
9769  */
9770  old_check_ok = (new_pathtype == old_pathtype &&
9771  new_castfunc == old_castfunc &&
9772  (!IsPolymorphicType(pfeqop_right) ||
9773  new_fktype == old_fktype));
9774  }
9775 
9776  pfeqoperators[i] = pfeqop;
9777  ppeqoperators[i] = ppeqop;
9778  ffeqoperators[i] = ffeqop;
9779  }
9780 
9781  /*
9782  * Create all the constraint and trigger objects, recursing to partitions
9783  * as necessary. First handle the referenced side.
9784  */
9785  address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
9786  indexOid,
9787  InvalidOid, /* no parent constraint */
9788  numfks,
9789  pkattnum,
9790  fkattnum,
9791  pfeqoperators,
9792  ppeqoperators,
9793  ffeqoperators,
9794  numfkdelsetcols,
9795  fkdelsetcols,
9796  old_check_ok,
9798 
9799  /* Now handle the referencing side. */
9800  addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
9801  indexOid,
9802  address.objectId,
9803  numfks,
9804  pkattnum,
9805  fkattnum,
9806  pfeqoperators,
9807  ppeqoperators,
9808  ffeqoperators,
9809  numfkdelsetcols,
9810  fkdelsetcols,
9811  old_check_ok,
9812  lockmode,
9814 
9815  /*
9816  * Done. Close pk table, but keep lock until we've committed.
9817  */
9818  table_close(pkrel, NoLock);
9819 
9820  return address;
9821 }
signed short int16
Definition: c.h:482
bool IsSystemRelation(Relation relation)
Definition: catalog.c:75
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
bool allowSystemTableMods
Definition: globals.c:124
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:165
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2503
bool can_coerce_type(int nargs, const Oid *input_typeids, const Oid *target_typeids, CoercionContext ccontext)
Definition: parse_coerce.c:556
CoercionPathType
Definition: parse_coerce.h:25
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2583
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2581
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2582
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
@ COERCION_IMPLICIT
Definition: primnodes.h:641
#define RelationIsPermanent(relation)
Definition: rel.h:618
TupleDesc oldDesc
Definition: tablecmds.c:165
List * pk_attrs
Definition: parsenodes.h:2635
List * fk_del_set_cols
Definition: parsenodes.h:2639
Oid old_pktable_oid
Definition: parsenodes.h:2641
List * old_conpfeqop
Definition: parsenodes.h:2640
RangeVar * pktable
Definition: parsenodes.h:2633
bool rd_islocaltemp
Definition: rel.h:61
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:868
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:820
@ CLAOID
Definition: syscache.h:48
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:83
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
Definition: tablecmds.c:11635
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:11869
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids)
Definition: tablecmds.c:11583
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:11898
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
Definition: tablecmds.c:11730
static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, int numfksetcols, const int16 *fksetcolsattnums, List *fksetcols)
Definition: tablecmds.c:9829
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define strVal(v)
Definition: value.h:82

References addFkRecurseReferenced(), addFkRecurseReferencing(), allowSystemTableMods, Assert(), BTEqualStrategyNumber, can_coerce_type(), checkFkeyPermissions(), CLAOID, COERCION_IMPLICIT, Constraint::conname, elog(), ereport, errcode(), errdetail(), errmsg(), ERROR, findFkeyCast(), Constraint::fk_attrs, Constraint::fk_del_action, Constraint::fk_del_set_cols, Constraint::fk_upd_action, FKCONSTR_ACTION_CASCADE, FKCONSTR_ACTION_SETDEFAULT, FKCONSTR_ACTION_SETNULL, format_type_be(), get_opfamily_member(), getBaseType(), GETSTRUCT, HeapTupleIsValid, i, INDEX_MAX_KEYS, Constraint::initially_valid, InvalidOid, IsSystemRelation(), lfirst_oid, list_head(), list_length(), list_nth(), lnext(), NIL, NoLock, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, Constraint::old_conpfeqop, Constraint::old_pktable_oid, AlteredTableInfo::oldDesc, Constraint::pk_attrs, Constraint::pktable, RelationData::rd_islocaltemp, RelationData::rd_rel, RelationGetDescr, RelationGetRelationName, RelationGetRelid, RelationIsPermanent, ReleaseSysCache(), SearchSysCache1(), ShareRowExclusiveLock, Constraint::skip_validation, strVal, table_close(), table_open(), table_openrv(), transformColumnNameList(), transformFkeyCheckAttrs(), transformFkeyGetPrimaryKey(), TupleDescAttr, and validateFkOnDeleteSetColumns().

Referenced by ATExecAddConstraint().

◆ ATCheckPartitionsNotInUse()

static void ATCheckPartitionsNotInUse ( Relation  rel,
LOCKMODE  lockmode 
)
static

Definition at line 6512 of file tablecmds.c.

6513 {
6514  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6515  {
6516  List *inh;
6517  ListCell *cell;
6518 
6519  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6520  /* first element is the parent rel; must ignore it */
6521  for_each_from(cell, inh, 1)
6522  {
6523  Relation childrel;
6524 
6525  /* find_all_inheritors already got lock */
6526  childrel = table_open(lfirst_oid(cell), NoLock);
6527  CheckTableNotInUse(childrel, "ALTER TABLE");
6528  table_close(childrel, NoLock);
6529  }
6530  list_free(inh);
6531  }
6532 }
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:256
#define for_each_from(cell, lst, N)
Definition: pg_list.h:414

References CheckTableNotInUse(), find_all_inheritors(), for_each_from, lfirst_oid, list_free(), NoLock, RelationData::rd_rel, RelationGetRelid, table_close(), and table_open().

Referenced by ATPrepCmd().

◆ ATColumnChangeRequiresRewrite()

static bool ATColumnChangeRequiresRewrite ( Node expr,
AttrNumber  varattno 
)
static

Definition at line 13024 of file tablecmds.c.

13025 {
13026  Assert(expr != NULL);
13027 
13028  for (;;)
13029  {
13030  /* only one varno, so no need to check that */
13031  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
13032  return false;
13033  else if (IsA(expr, RelabelType))
13034  expr = (Node *) ((RelabelType *) expr)->arg;
13035  else if (IsA(expr, CoerceToDomain))
13036  {
13037  CoerceToDomain *d = (CoerceToDomain *) expr;
13038 
13040  return true;
13041  expr = (Node *) d->arg;
13042  }
13043  else if (IsA(expr, FuncExpr))
13044  {
13045  FuncExpr *f = (FuncExpr *) expr;
13046 
13047  switch (f->funcid)
13048  {
13049  case F_TIMESTAMPTZ_TIMESTAMP:
13050  case F_TIMESTAMP_TIMESTAMPTZ:
13052  return true;
13053  else
13054  expr = linitial(f->args);
13055  break;
13056  default:
13057  return true;
13058  }
13059  }
13060  else
13061  return true;
13062  }
13063 }
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:5530
void * arg
#define linitial(l)
Definition: pg_list.h:178
Oid funcid
Definition: primnodes.h:677
List * args
Definition: primnodes.h:695
Definition: primnodes.h:226
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1397

References arg, CoerceToDomain::arg, FuncExpr::args, Assert(), DomainHasConstraints(), FuncExpr::funcid, IsA, linitial, CoerceToDomain::resulttype, and TimestampTimestampTzRequiresRewrite().

Referenced by ATPrepAlterColumnType().

◆ ATController()

static void ATController ( AlterTableStmt parsetree,
Relation  rel,
List cmds,
bool  recurse,
LOCKMODE  lockmode,
AlterTableUtilityContext context 
)
static

Definition at line 4606 of file tablecmds.c.

4609 {
4610  List *wqueue = NIL;
4611  ListCell *lcmd;
4612 
4613  /* Phase 1: preliminary examination of commands, create work queue */
4614  foreach(lcmd, cmds)
4615  {
4616  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4617 
4618  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4619  }
4620 
4621  /* Close the relation, but keep lock until commit */
4622  relation_close(rel, NoLock);
4623 
4624  /* Phase 2: update system catalogs */
4625  ATRewriteCatalogs(&wqueue, lockmode, context);
4626 
4627  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4628  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4629 }
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5017
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4641
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5555

References ATPrepCmd(), ATRewriteCatalogs(), ATRewriteTables(), lfirst, NIL, NoLock, and relation_close().

Referenced by AlterTable(), and AlterTableInternal().

◆ ATDetachCheckNoForeignKeyRefs()

static void ATDetachCheckNoForeignKeyRefs ( Relation  partition)
static

Definition at line 19997 of file tablecmds.c.

19998 {
19999  List *constraints;
20000  ListCell *cell;
20001 
20002  constraints = GetParentedForeignKeyRefs(partition);
20003 
20004  foreach(cell, constraints)
20005  {
20006  Oid constrOid = lfirst_oid(cell);
20007  HeapTuple tuple;
20008  Form_pg_constraint constrForm;
20009  Relation rel;
20010  Trigger trig = {0};
20011 
20012  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
20013  if (!HeapTupleIsValid(tuple))
20014  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
20015  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
20016 
20017  Assert(OidIsValid(constrForm->conparentid));
20018  Assert(constrForm->confrelid == RelationGetRelid(partition));
20019 
20020  /* prevent data changes into the referencing table until commit */
20021  rel = table_open(constrForm->conrelid, ShareLock);
20022 
20023  trig.tgoid = InvalidOid;
20024  trig.tgname = NameStr(constrForm->conname);
20026  trig.tgisinternal = true;
20027  trig.tgconstrrelid = RelationGetRelid(partition);
20028  trig.tgconstrindid = constrForm->conindid;
20029  trig.tgconstraint = constrForm->oid;
20030  trig.tgdeferrable = false;
20031  trig.tginitdeferred = false;
20032  /* we needn't fill in remaining fields */
20033 
20034  RI_PartitionRemove_Check(&trig, rel, partition);
20035 
20036  ReleaseSysCache(tuple);
20037 
20038  table_close(rel, NoLock);
20039  }
20040 }
#define ShareLock
Definition: lockdefs.h:40
FormData_pg_constraint * Form_pg_constraint
void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1663
char tgenabled
Definition: reltrigger.h:30
Oid tgoid
Definition: reltrigger.h:25
Oid tgconstrindid
Definition: reltrigger.h:34
Oid tgconstraint
Definition: reltrigger.h:35
Oid tgconstrrelid
Definition: reltrigger.h:33
char * tgname
Definition: reltrigger.h:27
bool tgdeferrable
Definition: reltrigger.h:36
bool tginitdeferred
Definition: reltrigger.h:37
bool tgisinternal
Definition: reltrigger.h:31
@ CONSTROID
Definition: syscache.h:53
static List * GetParentedForeignKeyRefs(Relation partition)
Definition: tablecmds.c:19944
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:149

References Assert(), CONSTROID, elog(), ERROR, GetParentedForeignKeyRefs(), GETSTRUCT, HeapTupleIsValid, InvalidOid, lfirst_oid, NameStr, NoLock, ObjectIdGetDatum(), OidIsValid, RelationGetRelid, ReleaseSysCache(), RI_PartitionRemove_Check(), SearchSysCache1(), ShareLock, table_close(), table_open(), Trigger::tgconstraint, Trigger::tgconstrindid, Trigger::tgconstrrelid, Trigger::tgdeferrable, Trigger::tgenabled, Trigger::tginitdeferred, Trigger::tgisinternal, Trigger::tgname, Trigger::tgoid, and TRIGGER_FIRES_ON_ORIGIN.

Referenced by ATExecDetachPartition().

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 17615 of file tablecmds.c.

17617 {
17618  ListCell *cur_item;
17619 
17620  foreach(cur_item, on_commits)
17621  {
17622  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
17623 
17624  if (!isCommit && oc->creating_subid == mySubid)
17625  {
17626  /* cur_item must be removed */
17628  pfree(oc);
17629  }
17630  else
17631  {
17632  /* cur_item must be preserved */
17633  if (oc->creating_subid == mySubid)
17634  oc->creating_subid = parentSubid;
17635  if (oc->deleting_subid == mySubid)
17636  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
17637  }
17638  }
17639 }
#define InvalidSubTransactionId
Definition: c.h:647
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:390
SubTransactionId creating_subid
Definition: tablecmds.c:124
SubTransactionId deleting_subid
Definition: tablecmds.c:125
static List * on_commits
Definition: tablecmds.c:128

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

17584 {
17585  ListCell *cur_item;
17586 
17587  foreach(cur_item, on_commits)
17588  {
17589  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
17590 
17591  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
17593  {
17594  /* cur_item must be removed */
17596  pfree(oc);
17597  }
17598  else
17599  {
17600  /* cur_item must be preserved */
17603  }
17604  }
17605 }

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

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

◆ ATExecAddColumn()

static ObjectAddress ATExecAddColumn ( List **  wqueue,
AlteredTableInfo tab,
Relation  rel,
AlterTableCmd **  cmd,
bool  recurse,
bool  recursing,
LOCKMODE  lockmode,
int  cur_pass,
AlterTableUtilityContext context 
)
static

Definition at line 6861 of file tablecmds.c.

6865 {
6866  Oid myrelid = RelationGetRelid(rel);
6867  ColumnDef *colDef = castNode(ColumnDef, (*cmd)->def);
6868  bool if_not_exists = (*cmd)->missing_ok;
6869  Relation pgclass,
6870  attrdesc;
6871  HeapTuple reltup;
6872  FormData_pg_attribute attribute;
6873  int newattnum;
6874  char relkind;
6875  HeapTuple typeTuple;
6876  Oid typeOid;
6877  int32 typmod;
6878  Oid collOid;
6879  Form_pg_type tform;
6880  Expr *defval;
6881  List *children;
6882  ListCell *child;
6883  AlterTableCmd *childcmd;
6884  AclResult aclresult;
6885  ObjectAddress address;
6886  TupleDesc tupdesc;
6887  FormData_pg_attribute *aattr[] = {&attribute};
6888 
6889  /* At top level, permission check was done in ATPrepCmd, else do it */
6890  if (recursing)
6891  ATSimplePermissions((*cmd)->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
6892 
6893  if (rel->rd_rel->relispartition && !recursing)
6894  ereport(ERROR,
6895  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6896  errmsg("cannot add column to a partition")));
6897 
6898  attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
6899 
6900  /*
6901  * Are we adding the column to a recursion child? If so, check whether to
6902  * merge with an existing definition for the column. If we do merge, we
6903  * must not recurse. Children will already have the column, and recursing
6904  * into them would mess up attinhcount.
6905  */
6906  if (colDef->inhcount > 0)
6907  {
6908  HeapTuple tuple;
6909 
6910  /* Does child already have a column by this name? */
6911  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
6912  if (HeapTupleIsValid(tuple))
6913  {
6914  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
6915  Oid ctypeId;
6916  int32 ctypmod;
6917  Oid ccollid;
6918 
6919  /* Child column must match on type, typmod, and collation */
6920  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
6921  if (ctypeId != childatt->atttypid ||
6922  ctypmod != childatt->atttypmod)
6923  ereport(ERROR,
6924  (errcode(ERRCODE_DATATYPE_MISMATCH),
6925  errmsg("child table \"%s\" has different type for column \"%s\"",
6926  RelationGetRelationName(rel), colDef->colname)));
6927  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
6928  if (ccollid != childatt->attcollation)
6929  ereport(ERROR,
6930  (errcode(ERRCODE_COLLATION_MISMATCH),
6931  errmsg("child table \"%s\" has different collation for column \"%s\"",
6932  RelationGetRelationName(rel), colDef->colname),
6933  errdetail("\"%s\" versus \"%s\"",
6934  get_collation_name(ccollid),
6935  get_collation_name(childatt->attcollation))));
6936 
6937  /* Bump the existing child att's inhcount */
6938  childatt->attinhcount++;
6939  if (childatt->attinhcount < 0)
6940  ereport(ERROR,
6941  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
6942  errmsg("too many inheritance parents"));
6943  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
6944 
6945  heap_freetuple(tuple);
6946 
6947  /* Inform the user about the merge */
6948  ereport(NOTICE,
6949  (errmsg("merging definition of column \"%s\" for child \"%s\"",
6950  colDef->colname, RelationGetRelationName(rel))));
6951 
6952  table_close(attrdesc, RowExclusiveLock);
6953  return InvalidObjectAddress;
6954  }
6955  }
6956 
6957  /* skip if the name already exists and if_not_exists is true */
6958  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
6959  {
6960  table_close(attrdesc, RowExclusiveLock);
6961  return InvalidObjectAddress;
6962  }
6963 
6964  /*
6965  * Okay, we need to add the column, so go ahead and do parse
6966  * transformation. This can result in queueing up, or even immediately
6967  * executing, subsidiary operations (such as creation of unique indexes);
6968  * so we mustn't do it until we have made the if_not_exists check.
6969  *
6970  * When recursing, the command was already transformed and we needn't do
6971  * so again. Also, if context isn't given we can't transform. (That
6972  * currently happens only for AT_AddColumnToView; we expect that view.c
6973  * passed us a ColumnDef that doesn't need work.)
6974  */
6975  if (context != NULL && !recursing)
6976  {
6977  *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
6978  cur_pass, context);
6979  Assert(*cmd != NULL);
6980  colDef = castNode(ColumnDef, (*cmd)->def);
6981  }
6982 
6983  /*
6984  * Cannot add identity column if table has children, because identity does
6985  * not inherit. (Adding column and identity separately will work.)
6986  */
6987  if (colDef->identity &&
6988  recurse &&
6989  find_inheritance_children(myrelid, NoLock) != NIL)
6990  ereport(ERROR,
6991  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6992  errmsg("cannot recursively add identity column to table that has child tables")));
6993 
6994  pgclass = table_open(RelationRelationId, RowExclusiveLock);
6995 
6996  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
6997  if (!HeapTupleIsValid(reltup))
6998  elog(ERROR, "cache lookup failed for relation %u", myrelid);
6999  relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
7000 
7001  /* Determine the new attribute's number */
7002  newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
7003  if (newattnum > MaxHeapAttributeNumber)
7004  ereport(ERROR,
7005  (errcode(ERRCODE_TOO_MANY_COLUMNS),
7006  errmsg("tables can have at most %d columns",
7008 
7009  typeTuple = typenameType(NULL, colDef->typeName, &typmod);
7010  tform = (Form_pg_type) GETSTRUCT(typeTuple);
7011  typeOid = tform->oid;
7012 
7013  aclresult = object_aclcheck(TypeRelationId, typeOid, GetUserId(), ACL_USAGE);
7014  if (aclresult != ACLCHECK_OK)
7015  aclcheck_error_type(aclresult, typeOid);
7016 
7017  collOid = GetColumnDefCollation(NULL, colDef, typeOid);
7018 
7019  /* make sure datatype is legal for a column */
7020  CheckAttributeType(colDef->colname, typeOid, collOid,
7021  list_make1_oid(rel->rd_rel->reltype),
7022  0);
7023 
7024  /*
7025  * Construct new attribute's pg_attribute entry. (Variable-length fields
7026  * are handled by InsertPgAttributeTuples().)
7027  */
7028  attribute.attrelid = myrelid;
7029  namestrcpy(&(attribute.attname), colDef->colname);
7030  attribute.atttypid = typeOid;
7031  attribute.attstattarget = -1;
7032  attribute.attlen = tform->typlen;
7033  attribute.attnum = newattnum;
7034  if (list_length(colDef->typeName->arrayBounds) > PG_INT16_MAX)
7035  ereport(ERROR,
7036  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
7037  errmsg("too many array dimensions"));
7038  attribute.attndims = list_length(colDef->typeName->arrayBounds);
7039  attribute.atttypmod = typmod;
7040  attribute.attbyval = tform->typbyval;
7041  attribute.attalign = tform->typalign;
7042  if (colDef->storage_name)
7043  attribute.attstorage = GetAttributeStorage(typeOid, colDef->storage_name);
7044  else
7045  attribute.attstorage = tform->typstorage;
7046  attribute.attcompression = GetAttributeCompression(typeOid,
7047  colDef->compression);
7048  attribute.attnotnull = colDef->is_not_null;
7049  attribute.atthasdef = false;
7050  attribute.atthasmissing = false;
7051  attribute.attidentity = colDef->identity;
7052  attribute.attgenerated = colDef->generated;
7053  attribute.attisdropped = false;
7054  attribute.attislocal = colDef->is_local;
7055  attribute.attinhcount = colDef->inhcount;
7056  attribute.attcollation = collOid;
7057 
7058  ReleaseSysCache(typeTuple);
7059 
7060  tupdesc = CreateTupleDesc(lengthof(aattr), (FormData_pg_attribute **) &aattr);
7061 
7062  InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
7063 
7064  table_close(attrdesc, RowExclusiveLock);
7065 
7066  /*
7067  * Update pg_class tuple as appropriate
7068  */
7069  ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
7070 
7071  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
7072 
7073  heap_freetuple(reltup);
7074 
7075  /* Post creation hook for new attribute */
7076  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
7077 
7078  table_close(pgclass, RowExclusiveLock);
7079 
7080  /* Make the attribute's catalog entry visible */
7082 
7083  /*
7084  * Store the DEFAULT, if any, in the catalogs
7085  */
7086  if (colDef->raw_default)
7087  {
7088  RawColumnDefault *rawEnt;
7089 
7090  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
7091  rawEnt->attnum = attribute.attnum;
7092  rawEnt->raw_default = copyObject(colDef->raw_default);
7093 
7094  /*
7095  * Attempt to skip a complete table rewrite by storing the specified
7096  * DEFAULT value outside of the heap. This may be disabled inside
7097  * AddRelationNewConstraints if the optimization cannot be applied.
7098  */
7099  rawEnt->missingMode = (!colDef->generated);
7100 
7101  rawEnt->generated = colDef->generated;
7102 
7103  /*
7104  * This function is intended for CREATE TABLE, so it processes a
7105  * _list_ of defaults, but we just do one.
7106  */
7108  false, true, false, NULL);
7109 
7110  /* Make the additional catalog changes visible */
7112 
7113  /*
7114  * Did the request for a missing value work? If not we'll have to do a
7115  * rewrite
7116  */
7117  if (!rawEnt->missingMode)
7119  }
7120 
7121  /*
7122  * Tell Phase 3 to fill in the default expression, if there is one.
7123  *
7124  * If there is no default, Phase 3 doesn't have to do anything, because
7125  * that effectively means that the default is NULL. The heap tuple access
7126  * routines always check for attnum > # of attributes in tuple, and return
7127  * NULL if so, so without any modification of the tuple data we will get
7128  * the effect of NULL values in the new column.
7129  *
7130  * An exception occurs when the new column is of a domain type: the domain
7131  * might have a not-null constraint, or a check constraint that indirectly
7132  * rejects nulls. If there are any domain constraints then we construct
7133  * an explicit NULL default value that will be passed through
7134  * CoerceToDomain processing. (This is a tad inefficient, since it causes
7135  * rewriting the table which we really don't have to do, but the present
7136  * design of domain processing doesn't offer any simple way of checking
7137  * the constraints more directly.)
7138  *
7139  * Note: we use build_column_default, and not just the cooked default
7140  * returned by AddRelationNewConstraints, so that the right thing happens
7141  * when a datatype's default applies.
7142  *
7143  * Note: it might seem that this should happen at the end of Phase 2, so
7144  * that the effects of subsequent subcommands can be taken into account.
7145  * It's intentional that we do it now, though. The new column should be
7146  * filled according to what is said in the ADD COLUMN subcommand, so that
7147  * the effects are the same as if this subcommand had been run by itself
7148  * and the later subcommands had been issued in new ALTER TABLE commands.
7149  *
7150  * We can skip this entirely for relations without storage, since Phase 3
7151  * is certainly not going to touch them. System attributes don't have
7152  * interesting defaults, either.
7153  */
7154  if (RELKIND_HAS_STORAGE(relkind))
7155  {
7156  /*
7157  * For an identity column, we can't use build_column_default(),
7158  * because the sequence ownership isn't set yet. So do it manually.
7159  */
7160  if (colDef->identity)
7161  {
7163 
7164  nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
7165  nve->typeId = typeOid;
7166 
7167  defval = (Expr *) nve;
7168 
7169  /* must do a rewrite for identity columns */
7171  }
7172  else
7173  defval = (Expr *) build_column_default(rel, attribute.attnum);
7174 
7175  if (!defval && DomainHasConstraints(typeOid))
7176  {
7177  Oid baseTypeId;
7178  int32 baseTypeMod;
7179  Oid baseTypeColl;
7180 
7181  baseTypeMod = typmod;
7182  baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
7183  baseTypeColl = get_typcollation(baseTypeId);
7184  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
7185  defval = (Expr *) coerce_to_target_type(NULL,
7186  (Node *) defval,
7187  baseTypeId,
7188  typeOid,
7189  typmod,
7192  -1);
7193  if (defval == NULL) /* should not happen */
7194  elog(ERROR, "failed to coerce base type to domain");
7195  }
7196 
7197  if (defval)
7198  {
7200 
7202  newval->attnum = attribute.attnum;
7203  newval->expr = expression_planner(defval);
7204  newval->is_generated = (colDef->generated != '\0');
7205 
7206  tab->newvals = lappend(tab->newvals, newval);
7207  }
7208 
7209  if (DomainHasConstraints(typeOid))
7211 
7212  if (!TupleDescAttr(rel->rd_att, attribute.attnum - 1)->atthasmissing)
7213  {
7214  /*
7215  * If the new column is NOT NULL, and there is no missing value,
7216  * tell Phase 3 it needs to check for NULLs.
7217  */
7218  tab->verify_new_notnull |= colDef->is_not_null;
7219  }
7220  }
7221 
7222  /*
7223  * Add needed dependency entries for the new column.
7224  */
7225  add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
7226  add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
7227 
7228  /*
7229  * Propagate to children as appropriate. Unlike most other ALTER
7230  * routines, we have to do this one level of recursion at a time; we can't
7231  * use find_all_inheritors to do it in one pass.
7232  */
7233  children =
7235 
7236  /*
7237  * If we are told not to recurse, there had better not be any child
7238  * tables; else the addition would put them out of step.
7239  */
7240  if (children && !recurse)
7241  ereport(ERROR,
7242  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7243  errmsg("column must be added to child tables too")));
7244 
7245  /* Children should see column as singly inherited */
7246  if (!recursing)
7247  {
7248  childcmd = copyObject(*cmd);
7249  colDef = castNode(ColumnDef, childcmd->def);
7250  colDef->inhcount = 1;
7251  colDef->is_local = false;
7252  }
7253  else
7254  childcmd = *cmd; /* no need to copy again */
7255 
7256  foreach(child, children)
7257  {
7258  Oid childrelid = lfirst_oid(child);
7259  Relation childrel;
7260  AlteredTableInfo *childtab;
7261 
7262  /* find_inheritance_children already got lock */
7263  childrel = table_open(childrelid, NoLock);
7264  CheckTableNotInUse(childrel, "ALTER TABLE");
7265 
7266  /* Find or create work queue entry for this table */
7267  childtab = ATGetQueueEntry(wqueue, childrel);
7268 
7269  /* Recurse to child; return value is ignored */
7270  ATExecAddColumn(wqueue, childtab, childrel,
7271  &childcmd, recurse, true,
7272  lockmode, cur_pass, context);
7273 
7274  table_close(childrel, NoLock);
7275  }
7276 
7277  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
7278  return address;
7279 }
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:2988
#define lengthof(array)
Definition: c.h:777
#define PG_INT16_MAX
Definition: c.h:575
#define AT_REWRITE_DEFAULT_VAL
Definition: event_trigger.h:35
#define newval
void InsertPgAttributeTuples(Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, const Datum *attoptions, CatalogIndexState indstate)
Definition: heap.c:697
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
Definition: heap.c:547
#define MaxHeapAttributeNumber
Definition: htup_details.h:48
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3038
char * get_collation_name(Oid colloid)
Definition: lsyscache.c:1061
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2520
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:340
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:79
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, Oid *typeid_p, int32 *typmod_p)
Definition: parse_type.c:310
Oid GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid)
Definition: parse_type.c:540
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:264
#define ACL_USAGE
Definition: parsenodes.h:91
FormData_pg_attribute
Definition: pg_attribute.h:193
#define list_make1_oid(x1)
Definition: pg_list.h:242
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
Expr * expression_planner(Expr *expr)
Definition: planner.c:6489
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:663
@ COERCION_ASSIGNMENT
Definition: primnodes.h:642
Node * build_column_default(Relation rel, int attrno)
bool verify_new_notnull
Definition: tablecmds.c:182
bool is_not_null
Definition: parsenodes.h:725
char identity
Definition: parsenodes.h:731
RangeVar * identitySequence
Definition: parsenodes.h:732
char * storage_name
Definition: parsenodes.h:728
int inhcount
Definition: parsenodes.h:723
char * colname
Definition: parsenodes.h:720
TypeName * typeName
Definition: parsenodes.h:721
char generated
Definition: parsenodes.h:734
Node * raw_default
Definition: parsenodes.h:729
bool is_local
Definition: parsenodes.h:724
char * compression
Definition: parsenodes.h:722
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
TupleDesc rd_att
Definition: rel.h:112
List * arrayBounds
Definition: parsenodes.h:271
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:984
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
Definition: tablecmds.c:7339
static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd **cmd, bool recurse, bool recursing, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:6861
static char GetAttributeCompression(Oid atttypid, const char *compression)
Definition: tablecmds.c:20046
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:7357
static AlterTableCmd * ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5418
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:7286
static char GetAttributeStorage(Oid atttypid, const char *storagemode)
Definition: tablecmds.c:20084
TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs)
Definition: tupdesc.c:90

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, add_column_collation_dependency(), add_column_datatype_dependency(), AddRelationNewConstraints(), TypeName::arrayBounds, Assert(), AT_REWRITE_DEFAULT_VAL, ATGetQueueEntry(), ATParseTransformCmd(), ATSimplePermissions(), ATT_FOREIGN_TABLE, ATT_TABLE, RawColumnDefault::attnum, build_column_default(), castNode, CatalogTupleUpdate(), check_for_column_name_collision(), CheckAttributeType(), CheckTableNotInUse(), COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, ColumnDef::colname, CommandCounterIncrement(), ColumnDef::compression, copyObject, CreateTupleDesc(), AlterTableCmd::def, DomainHasConstraints(), elog(), ereport, errcode(), errdetail(), errmsg(), ERROR, expression_planner(), find_inheritance_children(), FormData_pg_attribute, RawColumnDefault::generated, ColumnDef::generated, get_collation_name(), get_typcollation(), GetAttributeCompression(), GetAttributeStorage(), getBaseTypeAndTypmod(), GetColumnDefCollation(), GETSTRUCT, GetUserId(), heap_freetuple(), HeapTupleIsValid, ColumnDef::identity, ColumnDef::identitySequence, ColumnDef::inhcount, InsertPgAttributeTuples(), InvalidObjectAddress, InvokeObjectPostCreateHook, ColumnDef::is_local, ColumnDef::is_not_null, lappend(), lengthof, lfirst_oid, list_length(), list_make1, list_make1_oid, makeNode, makeNullConst(), MaxHeapAttributeNumber, RawColumnDefault::missingMode, namestrcpy(), newval, AlteredTableInfo::newvals, NIL, NoLock, NOTICE, object_aclcheck(), ObjectAddressSubSet, ObjectIdGetDatum(), palloc(), palloc0(), PG_INT16_MAX, RangeVarGetRelid, RawColumnDefault::raw_default, ColumnDef::raw_default, RelationData::rd_att, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), RELOID, AlteredTableInfo::rewrite, RowExclusiveLock, SearchSysCacheCopy1, SearchSysCacheCopyAttName(), NextValueExpr::seqid, ColumnDef::storage_name, HeapTupleData::t_self, table_close(), table_open(), TupleDescAttr, NextValueExpr::typeId, ColumnDef::typeName, typenameType(), typenameTypeIdAndMod(), and AlteredTableInfo::verify_new_notnull.

Referenced by ATExecCmd().

◆ ATExecAddConstraint()

static ObjectAddress ATExecAddConstraint ( List **  wqueue,
AlteredTableInfo tab,
Relation  rel,
Constraint newConstraint,
bool  recurse,
bool  is_readd,
LOCKMODE  lockmode 
)
static

Definition at line 9133 of file tablecmds.c.

9136 {
9138 
9139  Assert(IsA(newConstraint, Constraint));
9140 
9141  /*
9142  * Currently, we only expect to see CONSTR_CHECK, CONSTR_NOTNULL and
9143  * CONSTR_FOREIGN nodes arriving here (see the preprocessing done in
9144  * parse_utilcmd.c).
9145  */
9146  switch (newConstraint->contype)
9147  {
9148  case CONSTR_CHECK:
9149  case CONSTR_NOTNULL:
9150  address =
9151  ATAddCheckNNConstraint(wqueue, tab, rel,
9152  newConstraint, recurse, false, is_readd,
9153  lockmode);
9154  break;
9155 
9156  case CONSTR_FOREIGN:
9157 
9158  /*
9159  * Assign or validate constraint name
9160  */
9161  if (newConstraint->conname)
9162  {
9164  RelationGetRelid(rel),
9165  newConstraint->conname))
9166  ereport(ERROR,
9168  errmsg("constraint \"%s\" for relation \"%s\" already exists",
9169  newConstraint->conname,
9170  RelationGetRelationName(rel))));
9171  }
9172  else
9173  newConstraint->conname =
9176  "fkey",
9177  RelationGetNamespace(rel),
9178  NIL);
9179 
9180  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
9181  newConstraint,
9182  recurse, false,
9183  lockmode);
9184  break;
9185 
9186  default:
9187  elog(ERROR, "unrecognized constraint type: %d",
9188  (int) newConstraint->contype);
9189  }
9190 
9191  return address;
9192 }
@ CONSTR_CHECK
Definition: parsenodes.h:2567
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:9404

References Assert(), ATAddCheckNNConstraint(), ATAddForeignKeyConstraint(), ChooseConstraintName(), ChooseForeignKeyConstraintNameAddition(), Constraint::conname, CONSTR_CHECK, CONSTR_FOREIGN, CONSTR_NOTNULL, CONSTRAINT_RELATION, ConstraintNameIsUsed(), Constraint::contype, elog(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, Constraint::fk_attrs, InvalidObjectAddress, IsA, NIL, RelationGetNamespace, RelationGetRelationName, and RelationGetRelid.

Referenced by ATExecCmd().

◆ ATExecAddIdentity()

static ObjectAddress ATExecAddIdentity ( Relation  rel,
const char *  colName,
Node def,
LOCKMODE  lockmode 
)
static

Definition at line 7981 of file tablecmds.c.

7983 {
7984  Relation attrelation;
7985  HeapTuple tuple;
7986  Form_pg_attribute attTup;
7988  ObjectAddress address;
7989  ColumnDef *cdef = castNode(ColumnDef, def);
7990 
7991  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7992 
7993  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7994  if (!HeapTupleIsValid(tuple))
7995  ereport(ERROR,
7996  (errcode(ERRCODE_UNDEFINED_COLUMN),
7997  errmsg("column \"%s\" of relation \"%s\" does not exist",
7998  colName, RelationGetRelationName(rel))));
7999  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8000  attnum = attTup->attnum;
8001 
8002  /* Can't alter a system attribute */
8003  if (attnum <= 0)
8004  ereport(ERROR,
8005  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8006  errmsg("cannot alter system column \"%s\"",
8007  colName)));
8008 
8009  /*
8010  * Creating a column as identity implies NOT NULL, so adding the identity
8011  * to an existing column that is not NOT NULL would create a state that
8012  * cannot be reproduced without contortions.
8013  */
8014  if (!attTup->attnotnull)
8015  ereport(ERROR,
8016  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8017  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
8018  colName, RelationGetRelationName(rel))));
8019 
8020  if (attTup->attidentity)
8021  ereport(ERROR,
8022  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8023  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
8024  colName, RelationGetRelationName(rel))));
8025 
8026  if (attTup->atthasdef)
8027  ereport(ERROR,
8028  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8029  errmsg("column \"%s\" of relation \"%s\" already has a default value",
8030  colName, RelationGetRelationName(rel))));
8031 
8032  attTup->attidentity = cdef->identity;
8033  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8034 
8035  InvokeObjectPostAlterHook(RelationRelationId,
8036  RelationGetRelid(rel),
8037  attTup->attnum);
8038  ObjectAddressSubSet(address, RelationRelationId,
8039  RelationGetRelid(rel), attnum);
8040  heap_freetuple(tuple);
8041 
8042  table_close(attrelation, RowExclusiveLock);
8043 
8044  return address;
8045 }

References attnum, castNode, CatalogTupleUpdate(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, ColumnDef::identity, InvokeObjectPostAlterHook, ObjectAddressSubSet, RelationGetRelationName, RelationGetRelid, RowExclusiveLock, SearchSysCacheCopyAttName(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by ATExecCmd().

◆ ATExecAddIndex()

static ObjectAddress ATExecAddIndex ( AlteredTableInfo tab,
Relation  rel,
IndexStmt stmt,
bool  is_rebuild,
LOCKMODE  lockmode 
)
static

Definition at line 8957 of file tablecmds.c.

8959 {
8960  bool check_rights;
8961  bool skip_build;
8962  bool quiet;
8963  ObjectAddress address;
8964 
8965  Assert(IsA(stmt, IndexStmt));
8966  Assert(!stmt->concurrent);
8967 
8968  /* The IndexStmt has already been through transformIndexStmt */
8969  Assert(stmt->transformed);
8970 
8971  /* suppress schema rights check when rebuilding existing index */
8972  check_rights = !is_rebuild;
8973  /* skip index build if phase 3 will do it or we're reusing an old one */
8974  skip_build = tab->rewrite > 0 || RelFileNumberIsValid(stmt->oldNumber);
8975  /* suppress notices when rebuilding existing index */
8976  quiet = is_rebuild;
8977 
8978  address = DefineIndex(RelationGetRelid(rel),
8979  stmt,
8980  InvalidOid, /* no predefined OID */
8981  InvalidOid, /* no parent index */
8982  InvalidOid, /* no parent constraint */
8983  -1, /* total_parts unknown */
8984  true, /* is_alter_table */
8985  check_rights,
8986  false, /* check_not_in_use - we did it already */
8987  skip_build,
8988  quiet);
8989 
8990  /*
8991  * If TryReuseIndex() stashed a relfilenumber for us, we used it for the
8992  * new index instead of building from scratch. Restore associated fields.
8993  * This may store InvalidSubTransactionId in both fields, in which case
8994  * relcache.c will assume it can rebuild the relcache entry. Hence, do
8995  * this after the CCI that made catalog rows visible to any rebuild. The
8996  * DROP of the old edition of this index will have scheduled the storage
8997  * for deletion at commit, so cancel that pending deletion.
8998  */
8999  if (RelFileNumberIsValid(stmt->oldNumber))
9000  {
9001  Relation irel = index_open(address.objectId, NoLock);
9002 
9003  irel->rd_createSubid = stmt->oldCreateSubid;
9004  irel->rd_firstRelfilelocatorSubid = stmt->oldFirstRelfilelocatorSubid;
9005  RelationPreserveStorage(irel->rd_locator, true);
9006  index_close(irel, NoLock);
9007  }
9008 
9009  return address;
9010 }
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 tableId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, int total_parts, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition: indexcmds.c:525
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
void RelationPreserveStorage(RelFileLocator rlocator, bool atCommit)
Definition: storage.c:250
SubTransactionId rd_firstRelfilelocatorSubid
Definition: rel.h:106
SubTransactionId rd_createSubid
Definition: rel.h:103
RelFileLocator rd_locator
Definition: rel.h:57

References Assert(), DefineIndex(), index_close(), index_open(), InvalidOid, IsA, NoLock, ObjectAddress::objectId, RelationData::rd_createSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_locator, RelationGetRelid, RelationPreserveStorage(), RelFileNumberIsValid, AlteredTableInfo::rewrite, and stmt.

Referenced by ATExecCmd().

◆ ATExecAddIndexConstraint()

static ObjectAddress ATExecAddIndexConstraint ( AlteredTableInfo tab,
Relation  rel,
IndexStmt stmt,
LOCKMODE  lockmode 
)
static

Definition at line 9041 of file tablecmds.c.

9043 {
9044  Oid index_oid = stmt->indexOid;
9045  Relation indexRel;
9046  char *indexName;
9047  IndexInfo *indexInfo;
9048  char *constraintName;
9049  char constraintType;
9050  ObjectAddress address;
9051  bits16 flags;
9052 
9053  Assert(IsA(stmt, IndexStmt));
9054  Assert(OidIsValid(index_oid));
9055  Assert(stmt->isconstraint);
9056 
9057  /*
9058  * Doing this on partitioned tables is not a simple feature to implement,
9059  * so let's punt for now.
9060  */
9061  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9062  ereport(ERROR,
9063  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9064  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
9065 
9066  indexRel = index_open(index_oid, AccessShareLock);
9067 
9068  indexName = pstrdup(RelationGetRelationName(indexRel));
9069 
9070  indexInfo = BuildIndexInfo(indexRel);
9071 
9072  /* this should have been checked at parse time */
9073  if (!indexInfo->ii_Unique)
9074  elog(ERROR, "index \"%s\" is not unique", indexName);
9075 
9076  /*
9077  * Determine name to assign to constraint. We require a constraint to
9078  * have the same name as the underlying index; therefore, use the index's
9079  * existing name as the default constraint name, and if the user
9080  * explicitly gives some other name for the constraint, rename the index
9081  * to match.
9082  */
9083  constraintName = stmt->idxname;
9084  if (constraintName == NULL)
9085  constraintName = indexName;
9086  else if (strcmp(constraintName, indexName) != 0)
9087  {
9088  ereport(NOTICE,
9089  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
9090  indexName, constraintName)));
9091  RenameRelationInternal(index_oid, constraintName, false, true);
9092  }
9093 
9094  /* Extra checks needed if making primary key */
9095  if (stmt->primary)
9096  index_check_primary_key(rel, indexInfo, true, stmt);
9097 
9098  /* Note we currently don't support EXCLUSION constraints here */
9099  if (stmt->primary)
9100  constraintType = CONSTRAINT_PRIMARY;
9101  else
9102  constraintType = CONSTRAINT_UNIQUE;
9103 
9104  /* Create the catalog entries for the constraint */
9107  (stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
9108  (stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
9109  (stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
9110 
9111  address = index_constraint_create(rel,
9112  index_oid,
9113  InvalidOid,
9114  indexInfo,
9115  constraintName,
9116  constraintType,
9117  flags,
9119  false); /* is_internal */
9120 
9121  index_close(indexRel, NoLock);
9122 
9123  return address;
9124 }
uint16 bits16
Definition: c.h:503
void index_check_primary_key(Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
Definition: index.c:206
ObjectAddress index_constraint_create(Relation heapRelation, Oid indexRelationId, Oid parentConstraintId, const IndexInfo *indexInfo, const char *constraintName, char constraintType, bits16 constr_flags, bool allow_system_table_mods, bool is_internal)
Definition: index.c:1903
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2426
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:92
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:93
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:90
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition: index.h:89
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:91
char * pstrdup(const char *in)
Definition: mcxt.c:1644
bool ii_Unique
Definition: execnodes.h:191
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:4040

References AccessShareLock, allowSystemTableMods, Assert(), BuildIndexInfo(), elog(), ereport, errcode(), errmsg(), ERROR, IndexInfo::ii_Unique, index_check_primary_key(), index_close(), INDEX_CONSTR_CREATE_DEFERRABLE, INDEX_CONSTR_CREATE_INIT_DEFERRED, INDEX_CONSTR_CREATE_MARK_AS_PRIMARY, INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS, INDEX_CONSTR_CREATE_UPDATE_INDEX, index_constraint_create(), index_open(), InvalidOid, IsA, NoLock, NOTICE, OidIsValid, pstrdup(), RelationData::rd_rel, RelationGetRelationName, RenameRelationInternal(), and stmt.

Referenced by ATExecCmd().

◆ ATExecAddInherit()

static ObjectAddress ATExecAddInherit ( Relation  child_rel,
RangeVar parent,
LOCKMODE  lockmode 
)
static

Definition at line 15431 of file tablecmds.c.

15432 {
15433  Relation parent_rel;
15434  List *children;
15435  ObjectAddress address;
15436  const char *trigger_name;
15437 
15438  /*
15439  * A self-exclusive lock is needed here. See the similar case in
15440  * MergeAttributes() for a full explanation.
15441  */
15442  parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
15443 
15444  /*
15445  * Must be owner of both parent and child -- child was checked by
15446  * ATSimplePermissions call in ATPrepCmd
15447  */
15449 
15450  /* Permanent rels cannot inherit from temporary ones */
15451  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15452  child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
15453  ereport(ERROR,
15454  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15455  errmsg("cannot inherit from temporary relation \"%s\"",
15456  RelationGetRelationName(parent_rel))));
15457 
15458  /* If parent rel is temp, it must belong to this session */
15459  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15460  !parent_rel->rd_islocaltemp)
15461  ereport(ERROR,
15462  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15463  errmsg("cannot inherit from temporary relation of another session")));
15464 
15465  /* Ditto for the child */
15466  if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15467  !child_rel->rd_islocaltemp)
15468  ereport(ERROR,
15469  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15470  errmsg("cannot inherit to temporary relation of another session")));
15471 
15472  /* Prevent partitioned tables from becoming inheritance parents */
15473  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15474  ereport(ERROR,
15475  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15476  errmsg("cannot inherit from partitioned table \"%s\"",
15477  parent->relname)));
15478 
15479  /* Likewise for partitions */
15480  if (parent_rel->rd_rel->relispartition)
15481  ereport(ERROR,
15482  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15483  errmsg("cannot inherit from a partition")));
15484 
15485  /*
15486  * Prevent circularity by seeing if proposed parent inherits from child.
15487  * (In particular, this disallows making a rel inherit from itself.)
15488  *
15489  * This is not completely bulletproof because of race conditions: in
15490  * multi-level inheritance trees, someone else could concurrently be
15491  * making another inheritance link that closes the loop but does not join
15492  * either of the rels we have locked. Preventing that seems to require
15493  * exclusive locks on the entire inheritance tree, which is a cure worse
15494  * than the disease. find_all_inheritors() will cope with circularity
15495  * anyway, so don't sweat it too much.
15496  *
15497  * We use weakest lock we can on child's children, namely AccessShareLock.
15498  */
15499  children = find_all_inheritors(RelationGetRelid(child_rel),
15500  AccessShareLock, NULL);
15501 
15502  if (list_member_oid(children, RelationGetRelid(parent_rel)))
15503  ereport(ERROR,
15504  (errcode(ERRCODE_DUPLICATE_TABLE),
15505  errmsg("circular inheritance not allowed"),
15506  errdetail("\"%s\" is already a child of \"%s\".",
15507  parent->relname,
15508  RelationGetRelationName(child_rel))));
15509 
15510  /*
15511  * If child_rel has row-level triggers with transition tables, we
15512  * currently don't allow it to become an inheritance child. See also
15513  * prohibitions in ATExecAttachPartition() and CreateTrigger().
15514  */
15515  trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
15516  if (trigger_name != NULL)
15517  ereport(ERROR,
15518  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15519  errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
15520  trigger_name, RelationGetRelationName(child_rel)),
15521  errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
15522 
15523  /* OK to create inheritance */
15524  CreateInheritance(child_rel, parent_rel);
15525 
15526  /*
15527  * If parent_rel has a primary key, then child_rel has not-null
15528  * constraints that make these columns as non nullable. Make those
15529  * constraints as inherited.
15530  */
15531  ATInheritAdjustNotNulls(parent_rel, child_rel, 1);
15532 
15533  ObjectAddressSet(address, RelationRelationId,
15534  RelationGetRelid(parent_rel));
15535 
15536  /* keep our lock on the parent relation until commit */
15537  table_close(parent_rel, NoLock);
15538 
15539  return address;
15540 }
char * relname
Definition: primnodes.h:74
TriggerDesc * trigdesc
Definition: rel.h:117
static void CreateInheritance(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:15550
static void ATInheritAdjustNotNulls(Relation parent_rel, Relation child_rel, int inhcount)
Definition: tablecmds.c:16297
const char * FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc)
Definition: trigger.c:2278

References AccessShareLock, AT_AddInherit, ATInheritAdjustNotNulls(), ATSimplePermissions(), ATT_FOREIGN_TABLE, ATT_TABLE, CreateInheritance(), ereport, errcode(), errdetail(), errmsg(), ERROR, find_all_inheritors(), FindTriggerIncompatibleWithInheritance(), list_member_oid(), NoLock, ObjectAddressSet, RelationData::rd_islocaltemp, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, RangeVar::relname, ShareUpdateExclusiveLock, table_close(), table_openrv(), and RelationData::trigdesc.

Referenced by ATExecCmd().

◆ ATExecAddOf()

static ObjectAddress ATExecAddOf ( Relation  rel,
const TypeName ofTypename,
LOCKMODE  lockmode 
)
static

Definition at line 16394 of file tablecmds.c.

16395 {
16396  Oid relid = RelationGetRelid(rel);
16397  Type typetuple;
16398  Form_pg_type typeform;
16399  Oid typeid;
16400  Relation inheritsRelation,
16401  relationRelation;
16402  SysScanDesc scan;
16403  ScanKeyData key;
16404  AttrNumber table_attno,
16405  type_attno;
16406  TupleDesc typeTupleDesc,
16407  tableTupleDesc;
16408  ObjectAddress tableobj,
16409  typeobj;
16410  HeapTuple classtuple;
16411 
16412  /* Validate the type. */
16413  typetuple = typenameType(NULL, ofTypename, NULL);
16414  check_of_type(typetuple);
16415  typeform = (Form_pg_type) GETSTRUCT(typetuple);
16416  typeid = typeform->oid;
16417 
16418  /* Fail if the table has any inheritance parents. */
16419  inheritsRelation = table_open(InheritsRelationId, AccessShareLock);
16420  ScanKeyInit(&key,
16421  Anum_pg_inherits_inhrelid,
16422  BTEqualStrategyNumber, F_OIDEQ,
16423  ObjectIdGetDatum(relid));
16424  scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
16425  true, NULL, 1, &key);
16427  ereport(ERROR,
16428  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16429  errmsg("typed tables cannot inherit")));
16430  systable_endscan(scan);
16431  table_close(inheritsRelation, AccessShareLock);
16432 
16433  /*
16434  * Check the tuple descriptors for compatibility. Unlike inheritance, we
16435  * require that the order also match. However, attnotnull need not match.
16436  */
16437  typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
16438  tableTupleDesc = RelationGetDescr(rel);
16439  table_attno = 1;
16440  for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
16441  {
16442  Form_pg_attribute type_attr,
16443  table_attr;
16444  const char *type_attname,
16445  *table_attname;
16446 
16447  /* Get the next non-dropped type attribute. */
16448  type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
16449  if (type_attr->attisdropped)
16450  continue;
16451  type_attname = NameStr(type_attr->attname);
16452 
16453  /* Get the next non-dropped table attribute. */
16454  do
16455  {
16456  if (table_attno > tableTupleDesc->natts)
16457  ereport(ERROR,
16458  (errcode(ERRCODE_DATATYPE_MISMATCH),
16459  errmsg("table is missing column \"%s\"",
16460  type_attname)));
16461  table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
16462  table_attno++;
16463  } while (table_attr->attisdropped);
16464  table_attname = NameStr(table_attr->attname);
16465 
16466  /* Compare name. */
16467  if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
16468  ereport(ERROR,
16469  (errcode(ERRCODE_DATATYPE_MISMATCH),
16470  errmsg("table has column \"%s\" where type requires \"%s\"",
16471  table_attname, type_attname)));
16472 
16473  /* Compare type. */
16474  if (table_attr->atttypid != type_attr->atttypid ||
16475  table_attr->atttypmod != type_attr->atttypmod ||
16476  table_attr->attcollation != type_attr->attcollation)
16477  ereport(ERROR,
16478  (errcode(ERRCODE_DATATYPE_MISMATCH),
16479  errmsg("table \"%s\" has different type for column \"%s\"",
16480  RelationGetRelationName(rel), type_attname)));
16481  }
16482  ReleaseTupleDesc(typeTupleDesc);
16483 
16484  /* Any remaining columns at the end of the table had better be dropped. */
16485  for (; table_attno <= tableTupleDesc->natts; table_attno++)
16486  {
16487  Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
16488  table_attno - 1);
16489 
16490  if (!table_attr->attisdropped)
16491  ereport(ERROR,
16492  (errcode(ERRCODE_DATATYPE_MISMATCH),
16493  errmsg("table has extra column \"%s\"",
16494  NameStr(table_attr->attname))));
16495  }
16496 
16497  /* If the table was already typed, drop the existing dependency. */
16498  if (rel->rd_rel->reloftype)
16499  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
16501 
16502  /* Record a dependency on the new type. */
16503  tableobj.classId = RelationRelationId;
16504  tableobj.objectId = relid;
16505  tableobj.objectSubId = 0;
16506  typeobj.classId = TypeRelationId;
16507  typeobj.objectId = typeid;
16508  typeobj.objectSubId = 0;
16509  recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
16510 
16511  /* Update pg_class.reloftype */
16512  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
16513  classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
16514  if (!HeapTupleIsValid(classtuple))
16515  elog(ERROR, "cache lookup failed for relation %u", relid);
16516  ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
16517  CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
16518 
16519  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
16520 
16521  heap_freetuple(classtuple);
16522  table_close(relationRelation, RowExclusiveLock);
16523 
16524  ReleaseSysCache(typetuple);
16525 
16526  return typeobj;
16527 }
#define NAMEDATALEN
static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
Definition: tablecmds.c:16342
void check_of_type(HeapTuple typetuple)
Definition: tablecmds.c:6794
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1830

References AccessShareLock, BTEqualStrategyNumber, CatalogTupleUpdate(), check_of_type(), ObjectAddress::classId, DEPENDENCY_NORMAL, drop_parent_dependency(), elog(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, sort-test::key, lookup_rowtype_tupdesc(), NAMEDATALEN, NameStr, TupleDescData::natts, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, RelationData::rd_rel, recordDependencyOn(), RelationGetDescr, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), ReleaseTupleDesc, RELOID, RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), TupleDescAttr, and typenameType().

Referenced by ATExecCmd().

◆ ATExecAddStatistics()

static ObjectAddress ATExecAddStatistics ( AlteredTableInfo tab,
Relation  rel,
CreateStatsStmt stmt,
bool  is_rebuild,
LOCKMODE  lockmode 
)
static

Definition at line 9020 of file tablecmds.c.

9022 {
9023  ObjectAddress address;
9024 
9026 
9027  /* The CreateStatsStmt has already been through transformStatsStmt */
9028  Assert(stmt->transformed);
9029 
9030  address = CreateStatistics(stmt);
9031 
9032  return address;
9033 }
ObjectAddress CreateStatistics(CreateStatsStmt *stmt)
Definition: statscmds.c:65

References Assert(), CreateStatistics(), IsA, and stmt.

Referenced by ATExecCmd().

◆ ATExecAlterColumnGenericOptions()

static ObjectAddress ATExecAlterColumnGenericOptions ( Relation  rel,
const char *  colName,
List options,
LOCKMODE  lockmode 
) <