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_policy.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_publication_rel.h"
#include "catalog/pg_rewrite.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/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_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.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_NUM_PASSES   (AT_PASS_MISC + 1)
 
#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 enum AlterTablePass AlterTablePass
 
typedef struct AlteredTableInfo AlteredTableInfo
 
typedef struct NewConstraint NewConstraint
 
typedef struct NewColumnValue NewColumnValue
 
typedef struct ForeignTruncateInfo ForeignTruncateInfo
 

Enumerations

enum  AlterTablePass {
  AT_PASS_UNSET = -1 , AT_PASS_DROP , AT_PASS_ALTER_TYPE , AT_PASS_ADD_COL ,
  AT_PASS_SET_EXPRESSION , AT_PASS_OLD_INDEX , AT_PASS_OLD_CONSTR , AT_PASS_ADD_CONSTR ,
  AT_PASS_COL_ATTRS , AT_PASS_ADD_INDEXCONSTR , AT_PASS_ADD_INDEX , AT_PASS_ADD_OTHERCONSTR ,
  AT_PASS_MISC
}
 

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)
 
static ListMergeCheckConstraint (List *constraints, const char *name, Node *expr)
 
static void MergeChildAttribute (List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef)
 
static ColumnDefMergeInheritedAttribute (List *inh_columns, int exist_attno, const ColumnDef *newdef)
 
static void MergeAttributesIntoExisting (Relation child_rel, Relation parent_rel, bool ispartition)
 
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 CheckAlterTableIsSafe (Relation rel)
 
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, AlterTablePass cur_pass, AlterTableUtilityContext *context)
 
static AlterTableCmdATParseTransformCmd (List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTablePass 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, AlterTablePass 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 void ATPrepDropNotNull (Relation rel, bool recurse, bool recursing)
 
static ObjectAddress ATExecDropNotNull (Relation rel, const char *colName, LOCKMODE lockmode)
 
static void ATPrepSetNotNull (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static ObjectAddress ATExecSetNotNull (AlteredTableInfo *tab, Relation rel, const char *colName, LOCKMODE lockmode)
 
static void ATExecCheckNotNull (AlteredTableInfo *tab, 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, bool recurse, bool recursing)
 
static ObjectAddress ATExecSetIdentity (Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
 
static ObjectAddress ATExecDropIdentity (Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode, bool recurse, bool recursing)
 
static ObjectAddress ATExecSetExpression (AlteredTableInfo *tab, Relation rel, const char *colName, Node *newExpr, 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 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 ATAddCheckConstraint (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 recursing, bool missing_ok, 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 RememberAllDependentForRebuilding (AlteredTableInfo *tab, AlterTableType subtype, Relation rel, AttrNumber attnum, const char *colName)
 
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, AlterTablePass 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 void ATExecSetAccessMethodNoStorage (Relation rel, Oid newAccessMethodId)
 
static void ATPrepChangePersistence (AlteredTableInfo *tab, 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, bool ispartition)
 
static void RemoveInheritance (Relation child_rel, Relation parent_rel, bool expect_detached)
 
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 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)
 
TupleDesc BuildDescForRelation (const List *columns)
 
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 RangeVarCallbackMaintainsTable (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   (AT_PASS_MISC + 1)

Definition at line 164 of file tablecmds.c.

◆ ATT_COMPOSITE_TYPE

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 329 of file tablecmds.c.

◆ ATT_FOREIGN_TABLE

#define ATT_FOREIGN_TABLE   0x0020

Definition at line 330 of file tablecmds.c.

◆ ATT_INDEX

#define ATT_INDEX   0x0008

Definition at line 328 of file tablecmds.c.

◆ ATT_MATVIEW

#define ATT_MATVIEW   0x0004

Definition at line 327 of file tablecmds.c.

◆ ATT_PARTITIONED_INDEX

#define ATT_PARTITIONED_INDEX   0x0040

Definition at line 331 of file tablecmds.c.

◆ ATT_SEQUENCE

#define ATT_SEQUENCE   0x0080

Definition at line 332 of file tablecmds.c.

◆ ATT_TABLE

#define ATT_TABLE   0x0001

Definition at line 325 of file tablecmds.c.

◆ ATT_VIEW

#define ATT_VIEW   0x0002

Definition at line 326 of file tablecmds.c.

◆ child_dependency_type

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

Definition at line 353 of file tablecmds.c.

Typedef Documentation

◆ AlteredTableInfo

◆ AlterTablePass

◆ ForeignTruncateInfo

◆ NewColumnValue

◆ NewConstraint

typedef struct NewConstraint NewConstraint

◆ OnCommitItem

typedef struct OnCommitItem OnCommitItem

Enumeration Type Documentation

◆ AlterTablePass

Enumerator
AT_PASS_UNSET 
AT_PASS_DROP 
AT_PASS_ALTER_TYPE 
AT_PASS_ADD_COL 
AT_PASS_SET_EXPRESSION 
AT_PASS_OLD_INDEX 
AT_PASS_OLD_CONSTR 
AT_PASS_ADD_CONSTR 
AT_PASS_COL_ATTRS 
AT_PASS_ADD_INDEXCONSTR 
AT_PASS_ADD_INDEX 
AT_PASS_ADD_OTHERCONSTR 
AT_PASS_MISC 

Definition at line 146 of file tablecmds.c.

147 {
148  AT_PASS_UNSET = -1, /* UNSET will cause ERROR */
149  AT_PASS_DROP, /* DROP (all flavors) */
150  AT_PASS_ALTER_TYPE, /* ALTER COLUMN TYPE */
151  AT_PASS_ADD_COL, /* ADD COLUMN */
152  AT_PASS_SET_EXPRESSION, /* ALTER SET EXPRESSION */
153  AT_PASS_OLD_INDEX, /* re-add existing indexes */
154  AT_PASS_OLD_CONSTR, /* re-add existing constraints */
155  /* We could support a RENAME COLUMN pass here, but not currently used */
156  AT_PASS_ADD_CONSTR, /* ADD constraints (initial examination) */
157  AT_PASS_COL_ATTRS, /* set column attributes, eg NOT NULL */
158  AT_PASS_ADD_INDEXCONSTR, /* ADD index-based constraints */
159  AT_PASS_ADD_INDEX, /* ADD indexes */
160  AT_PASS_ADD_OTHERCONSTR, /* ADD other constraints, defaults */
161  AT_PASS_MISC, /* other stuff */
AlterTablePass
Definition: tablecmds.c:147
@ AT_PASS_ADD_CONSTR
Definition: tablecmds.c:156
@ AT_PASS_ADD_OTHERCONSTR
Definition: tablecmds.c:160
@ AT_PASS_OLD_CONSTR
Definition: tablecmds.c:154
@ AT_PASS_ADD_COL
Definition: tablecmds.c:151
@ AT_PASS_OLD_INDEX
Definition: tablecmds.c:153
@ AT_PASS_ALTER_TYPE
Definition: tablecmds.c:150
@ AT_PASS_ADD_INDEXCONSTR
Definition: tablecmds.c:158
@ AT_PASS_DROP
Definition: tablecmds.c:149
@ AT_PASS_MISC
Definition: tablecmds.c:161
@ AT_PASS_COL_ATTRS
Definition: tablecmds.c:157
@ AT_PASS_SET_EXPRESSION
Definition: tablecmds.c:152
@ AT_PASS_ADD_INDEX
Definition: tablecmds.c:159
@ AT_PASS_UNSET
Definition: tablecmds.c:148

Function Documentation

◆ add_column_collation_dependency()

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

Definition at line 7424 of file tablecmds.c.

7425 {
7426  ObjectAddress myself,
7427  referenced;
7428 
7429  /* We know the default collation is pinned, so don't bother recording it */
7430  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7431  {
7432  myself.classId = RelationRelationId;
7433  myself.objectId = relid;
7434  myself.objectSubId = attnum;
7435  referenced.classId = CollationRelationId;
7436  referenced.objectId = collid;
7437  referenced.objectSubId = 0;
7438  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7439  }
7440 }
#define OidIsValid(objectId)
Definition: c.h:775
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:46

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

7407 {
7408  ObjectAddress myself,
7409  referenced;
7410 
7411  myself.classId = RelationRelationId;
7412  myself.objectId = relid;
7413  myself.objectSubId = attnum;
7414  referenced.classId = TypeRelationId;
7415  referenced.objectId = typid;
7416  referenced.objectSubId = 0;
7417  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7418 }

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

10018 {
10019  ObjectAddress address;
10020  Oid constrOid;
10021  char *conname;
10022  bool conislocal;
10023  int coninhcount;
10024  bool connoinherit;
10025  Oid deleteTriggerOid,
10026  updateTriggerOid;
10027 
10028  /*
10029  * Verify relkind for each referenced partition. At the top level, this
10030  * is redundant with a previous check, but we need it when recursing.
10031  */
10032  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
10033  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
10034  ereport(ERROR,
10035  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10036  errmsg("referenced relation \"%s\" is not a table",
10037  RelationGetRelationName(pkrel))));
10038 
10039  /*
10040  * Caller supplies us with a constraint name; however, it may be used in
10041  * this partition, so come up with a different one in that case.
10042  */
10044  RelationGetRelid(rel),
10045  fkconstraint->conname))
10048  "fkey",
10049  RelationGetNamespace(rel), NIL);
10050  else
10051  conname = fkconstraint->conname;
10052 
10053  if (OidIsValid(parentConstr))
10054  {
10055  conislocal = false;
10056  coninhcount = 1;
10057  connoinherit = false;
10058  }
10059  else
10060  {
10061  conislocal = true;
10062  coninhcount = 0;
10063 
10064  /*
10065  * always inherit for partitioned tables, never for legacy inheritance
10066  */
10067  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
10068  }
10069 
10070  /*
10071  * Record the FK constraint in pg_constraint.
10072  */
10073  constrOid = CreateConstraintEntry(conname,
10074  RelationGetNamespace(rel),
10075  CONSTRAINT_FOREIGN,
10076  fkconstraint->deferrable,
10077  fkconstraint->initdeferred,
10078  fkconstraint->initially_valid,
10079  parentConstr,
10080  RelationGetRelid(rel),
10081  fkattnum,
10082  numfks,
10083  numfks,
10084  InvalidOid, /* not a domain constraint */
10085  indexOid,
10086  RelationGetRelid(pkrel),
10087  pkattnum,
10088  pfeqoperators,
10089  ppeqoperators,
10090  ffeqoperators,
10091  numfks,
10092  fkconstraint->fk_upd_action,
10093  fkconstraint->fk_del_action,
10094  fkdelsetcols,
10095  numfkdelsetcols,
10096  fkconstraint->fk_matchtype,
10097  NULL, /* no exclusion constraint */
10098  NULL, /* no check constraint */
10099  NULL,
10100  conislocal, /* islocal */
10101  coninhcount, /* inhcount */
10102  connoinherit, /* conNoInherit */
10103  false); /* is_internal */
10104 
10105  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10106 
10107  /*
10108  * Mark the child constraint as part of the parent constraint; it must not
10109  * be dropped on its own. (This constraint is deleted when the partition
10110  * is detached, but a special check needs to occur that the partition
10111  * contains no referenced values.)
10112  */
10113  if (OidIsValid(parentConstr))
10114  {
10115  ObjectAddress referenced;
10116 
10117  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
10118  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
10119  }
10120 
10121  /* make new constraint visible, in case we add more */
10123 
10124  /*
10125  * Create the action triggers that enforce the constraint.
10126  */
10128  fkconstraint,
10129  constrOid, indexOid,
10130  parentDelTrigger, parentUpdTrigger,
10131  &deleteTriggerOid, &updateTriggerOid);
10132 
10133  /*
10134  * If the referenced table is partitioned, recurse on ourselves to handle
10135  * each partition. We need one pg_constraint row created for each
10136  * partition in addition to the pg_constraint row for the parent table.
10137  */
10138  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10139  {
10140  PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
10141 
10142  for (int i = 0; i < pd->nparts; i++)
10143  {
10144  Relation partRel;
10145  AttrMap *map;
10146  AttrNumber *mapped_pkattnum;
10147  Oid partIndexId;
10148 
10149  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
10150 
10151  /*
10152  * Map the attribute numbers in the referenced side of the FK
10153  * definition to match the partition's column layout.
10154  */
10156  RelationGetDescr(pkrel),
10157  false);
10158  if (map)
10159  {
10160  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
10161  for (int j = 0; j < numfks; j++)
10162  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
10163  }
10164  else
10165  mapped_pkattnum = pkattnum;
10166 
10167  /* do the deed */
10168  partIndexId = index_get_partition(partRel, indexOid);
10169  if (!OidIsValid(partIndexId))
10170  elog(ERROR, "index for %u not found in partition %s",
10171  indexOid, RelationGetRelationName(partRel));
10172  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
10173  partIndexId, constrOid, numfks,
10174  mapped_pkattnum, fkattnum,
10175  pfeqoperators, ppeqoperators, ffeqoperators,
10176  numfkdelsetcols, fkdelsetcols,
10177  old_check_ok,
10178  deleteTriggerOid, updateTriggerOid);
10179 
10180  /* Done -- clean up (but keep the lock) */
10181  table_close(partRel, NoLock);
10182  if (map)
10183  {
10184  pfree(mapped_pkattnum);
10185  free_attrmap(map);
10186  }
10187  }
10188  }
10189 
10190  return address;
10191 }
void free_attrmap(AttrMap *map)
Definition: attmap.c:56
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:263
int16 AttrNumber
Definition: attnum.h:21
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#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:1521
void * palloc(Size size)
Definition: mcxt.c:1317
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:71
Oid index_get_partition(Relation partition, Oid indexId)
Definition: partition.c:176
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:48
@ 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:505
#define RelationGetDescr(relation)
Definition: rel.h:531
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationGetNamespace(relation)
Definition: rel.h:546
Definition: attmap.h:35
AttrNumber * attnums
Definition: attmap.h:36
bool initdeferred
Definition: parsenodes.h:2724
char fk_upd_action
Definition: parsenodes.h:2755
char fk_matchtype
Definition: parsenodes.h:2754
bool initially_valid
Definition: parsenodes.h:2726
bool deferrable
Definition: parsenodes.h:2723
char * conname
Definition: parsenodes.h:2722
char fk_del_action
Definition: parsenodes.h:2756
List * fk_attrs
Definition: parsenodes.h:2752
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:9344
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12231
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:10010
void CommandCounterIncrement(void)
Definition: xact.c:1099

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

10237 {
10238  Oid insertTriggerOid,
10239  updateTriggerOid;
10240 
10241  Assert(OidIsValid(parentConstr));
10242 
10243  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
10244  ereport(ERROR,
10245  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10246  errmsg("foreign key constraints are not supported on foreign tables")));
10247 
10248  /*
10249  * Add the check triggers to it and, if necessary, schedule it to be
10250  * checked in Phase 3.
10251  *
10252  * If the relation is partitioned, drill down to do it to its partitions.
10253  */
10255  RelationGetRelid(pkrel),
10256  fkconstraint,
10257  parentConstr,
10258  indexOid,
10259  parentInsTrigger, parentUpdTrigger,
10260  &insertTriggerOid, &updateTriggerOid);
10261 
10262  if (rel->rd_rel->relkind == RELKIND_RELATION)
10263  {
10264  /*
10265  * Tell Phase 3 to check that the constraint is satisfied by existing
10266  * rows. We can skip this during table creation, when requested
10267  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
10268  * and when we're recreating a constraint following a SET DATA TYPE
10269  * operation that did not impugn its validity.
10270  */
10271  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
10272  {
10273  NewConstraint *newcon;
10274  AlteredTableInfo *tab;
10275 
10276  tab = ATGetQueueEntry(wqueue, rel);
10277 
10278  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
10279  newcon->name = get_constraint_name(parentConstr);
10280  newcon->contype = CONSTR_FOREIGN;
10281  newcon->refrelid = RelationGetRelid(pkrel);
10282  newcon->refindid = indexOid;
10283  newcon->conid = parentConstr;
10284  newcon->qual = (Node *) fkconstraint;
10285 
10286  tab->constraints = lappend(tab->constraints, newcon);
10287  }
10288  }
10289  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10290  {
10291  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
10292  Relation trigrel;
10293 
10294  /*
10295  * Triggers of the foreign keys will be manipulated a bunch of times
10296  * in the loop below. To avoid repeatedly opening/closing the trigger
10297  * catalog relation, we open it here and pass it to the subroutines
10298  * called below.
10299  */
10300  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10301 
10302  /*
10303  * Recurse to take appropriate action on each partition; either we
10304  * find an existing constraint to reparent to ours, or we create a new
10305  * one.
10306  */
10307  for (int i = 0; i < pd->nparts; i++)
10308  {
10309  Oid partitionId = pd->oids[i];
10310  Relation partition = table_open(partitionId, lockmode);
10311  List *partFKs;
10312  AttrMap *attmap;
10313  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
10314  bool attached;
10315  char *conname;
10316  Oid constrOid;
10317  ObjectAddress address,
10318  referenced;
10319  ListCell *cell;
10320 
10321  CheckAlterTableIsSafe(partition);
10322 
10323  attmap = build_attrmap_by_name(RelationGetDescr(partition),
10324  RelationGetDescr(rel),
10325  false);
10326  for (int j = 0; j < numfks; j++)
10327  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
10328 
10329  /* Check whether an existing constraint can be repurposed */
10330  partFKs = copyObject(RelationGetFKeyList(partition));
10331  attached = false;
10332  foreach(cell, partFKs)
10333  {
10334  ForeignKeyCacheInfo *fk;
10335 
10336  fk = lfirst_node(ForeignKeyCacheInfo, cell);
10338  partitionId,
10339  parentConstr,
10340  numfks,
10341  mapped_fkattnum,
10342  pkattnum,
10343  pfeqoperators,
10344  insertTriggerOid,
10345  updateTriggerOid,
10346  trigrel))
10347  {
10348  attached = true;
10349  break;
10350  }
10351  }
10352  if (attached)
10353  {
10354  table_close(partition, NoLock);
10355  continue;
10356  }
10357 
10358  /*
10359  * No luck finding a good constraint to reuse; create our own.
10360  */
10362  RelationGetRelid(partition),
10363  fkconstraint->conname))
10364  conname = ChooseConstraintName(RelationGetRelationName(partition),
10366  "fkey",
10367  RelationGetNamespace(partition), NIL);
10368  else
10369  conname = fkconstraint->conname;
10370  constrOid =
10371  CreateConstraintEntry(conname,
10372  RelationGetNamespace(partition),
10373  CONSTRAINT_FOREIGN,
10374  fkconstraint->deferrable,
10375  fkconstraint->initdeferred,
10376  fkconstraint->initially_valid,
10377  parentConstr,
10378  partitionId,
10379  mapped_fkattnum,
10380  numfks,
10381  numfks,
10382  InvalidOid,
10383  indexOid,
10384  RelationGetRelid(pkrel),
10385  pkattnum,
10386  pfeqoperators,
10387  ppeqoperators,
10388  ffeqoperators,
10389  numfks,
10390  fkconstraint->fk_upd_action,
10391  fkconstraint->fk_del_action,
10392  fkdelsetcols,
10393  numfkdelsetcols,
10394  fkconstraint->fk_matchtype,
10395  NULL,
10396  NULL,
10397  NULL,
10398  false,
10399  1,
10400  false,
10401  false);
10402 
10403  /*
10404  * Give this constraint partition-type dependencies on the parent
10405  * constraint as well as the table.
10406  */
10407  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10408  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
10409  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
10410  ObjectAddressSet(referenced, RelationRelationId, partitionId);
10411  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
10412 
10413  /* Make all this visible before recursing */
10415 
10416  /* call ourselves to finalize the creation and we're done */
10417  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
10418  indexOid,
10419  constrOid,
10420  numfks,
10421  pkattnum,
10422  mapped_fkattnum,
10423  pfeqoperators,
10424  ppeqoperators,
10425  ffeqoperators,
10426  numfkdelsetcols,
10427  fkdelsetcols,
10428  old_check_ok,
10429  lockmode,
10430  insertTriggerOid,
10431  updateTriggerOid);
10432 
10433  table_close(partition, NoLock);
10434  }
10435 
10436  table_close(trigrel, RowExclusiveLock);
10437  }
10438 }
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:177
#define Assert(condition)
Definition: c.h:858
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
List * lappend(List *list, void *datum)
Definition: list.c:339
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1081
void * palloc0(Size size)
Definition: mcxt.c:1347
#define copyObject(obj)
Definition: nodes.h:224
@ CONSTR_FOREIGN
Definition: parsenodes.h:2699
#define INDEX_MAX_KEYS
#define lfirst_node(type, lc)
Definition: pg_list.h:176
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4692
List * constraints
Definition: tablecmds.c:185
bool skip_validation
Definition: parsenodes.h:2725
Definition: pg_list.h:54
char * name
Definition: tablecmds.c:214
ConstrType contype
Definition: tablecmds.c:215
Node * qual
Definition: tablecmds.c:219
Definition: nodes.h:129
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:6303
static void CheckAlterTableIsSafe(Relation rel)
Definition: tablecmds.c:4273
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:10975
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:10230
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12366

References Assert, ATGetQueueEntry(), AttrMap::attnums, build_attrmap_by_name(), CheckAlterTableIsSafe(), 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 6337 of file tablecmds.c.

6338 {
6339  switch (cmdtype)
6340  {
6341  case AT_AddColumn:
6342  case AT_AddColumnToView:
6343  return "ADD COLUMN";
6344  case AT_ColumnDefault:
6346  return "ALTER COLUMN ... SET DEFAULT";
6347  case AT_DropNotNull:
6348  return "ALTER COLUMN ... DROP NOT NULL";
6349  case AT_SetNotNull:
6350  return "ALTER COLUMN ... SET NOT NULL";
6351  case AT_SetExpression:
6352  return "ALTER COLUMN ... SET EXPRESSION";
6353  case AT_DropExpression:
6354  return "ALTER COLUMN ... DROP EXPRESSION";
6355  case AT_CheckNotNull:
6356  return NULL; /* not real grammar */
6357  case AT_SetStatistics:
6358  return "ALTER COLUMN ... SET STATISTICS";
6359  case AT_SetOptions:
6360  return "ALTER COLUMN ... SET";
6361  case AT_ResetOptions:
6362  return "ALTER COLUMN ... RESET";
6363  case AT_SetStorage:
6364  return "ALTER COLUMN ... SET STORAGE";
6365  case AT_SetCompression:
6366  return "ALTER COLUMN ... SET COMPRESSION";
6367  case AT_DropColumn:
6368  return "DROP COLUMN";
6369  case AT_AddIndex:
6370  case AT_ReAddIndex:
6371  return NULL; /* not real grammar */
6372  case AT_AddConstraint:
6373  case AT_ReAddConstraint:
6375  case AT_AddIndexConstraint:
6376  return "ADD CONSTRAINT";
6377  case AT_AlterConstraint:
6378  return "ALTER CONSTRAINT";
6379  case AT_ValidateConstraint:
6380  return "VALIDATE CONSTRAINT";
6381  case AT_DropConstraint:
6382  return "DROP CONSTRAINT";
6383  case AT_ReAddComment:
6384  return NULL; /* not real grammar */
6385  case AT_AlterColumnType:
6386  return "ALTER COLUMN ... SET DATA TYPE";
6388  return "ALTER COLUMN ... OPTIONS";
6389  case AT_ChangeOwner:
6390  return "OWNER TO";
6391  case AT_ClusterOn:
6392  return "CLUSTER ON";
6393  case AT_DropCluster:
6394  return "SET WITHOUT CLUSTER";
6395  case AT_SetAccessMethod:
6396  return "SET ACCESS METHOD";
6397  case AT_SetLogged:
6398  return "SET LOGGED";
6399  case AT_SetUnLogged:
6400  return "SET UNLOGGED";
6401  case AT_DropOids:
6402  return "SET WITHOUT OIDS";
6403  case AT_SetTableSpace:
6404  return "SET TABLESPACE";
6405  case AT_SetRelOptions:
6406  return "SET";
6407  case AT_ResetRelOptions:
6408  return "RESET";
6409  case AT_ReplaceRelOptions:
6410  return NULL; /* not real grammar */
6411  case AT_EnableTrig:
6412  return "ENABLE TRIGGER";
6413  case AT_EnableAlwaysTrig:
6414  return "ENABLE ALWAYS TRIGGER";
6415  case AT_EnableReplicaTrig:
6416  return "ENABLE REPLICA TRIGGER";
6417  case AT_DisableTrig:
6418  return "DISABLE TRIGGER";
6419  case AT_EnableTrigAll:
6420  return "ENABLE TRIGGER ALL";
6421  case AT_DisableTrigAll:
6422  return "DISABLE TRIGGER ALL";
6423  case AT_EnableTrigUser:
6424  return "ENABLE TRIGGER USER";
6425  case AT_DisableTrigUser:
6426  return "DISABLE TRIGGER USER";
6427  case AT_EnableRule:
6428  return "ENABLE RULE";
6429  case AT_EnableAlwaysRule:
6430  return "ENABLE ALWAYS RULE";
6431  case AT_EnableReplicaRule:
6432  return "ENABLE REPLICA RULE";
6433  case AT_DisableRule:
6434  return "DISABLE RULE";
6435  case AT_AddInherit:
6436  return "INHERIT";
6437  case AT_DropInherit:
6438  return "NO INHERIT";
6439  case AT_AddOf:
6440  return "OF";
6441  case AT_DropOf:
6442  return "NOT OF";
6443  case AT_ReplicaIdentity:
6444  return "REPLICA IDENTITY";
6445  case AT_EnableRowSecurity:
6446  return "ENABLE ROW SECURITY";
6447  case AT_DisableRowSecurity:
6448  return "DISABLE ROW SECURITY";
6449  case AT_ForceRowSecurity:
6450  return "FORCE ROW SECURITY";
6451  case AT_NoForceRowSecurity:
6452  return "NO FORCE ROW SECURITY";
6453  case AT_GenericOptions:
6454  return "OPTIONS";
6455  case AT_AttachPartition:
6456  return "ATTACH PARTITION";
6457  case AT_DetachPartition:
6458  return "DETACH PARTITION";
6460  return "DETACH PARTITION ... FINALIZE";
6461  case AT_AddIdentity:
6462  return "ALTER COLUMN ... ADD IDENTITY";
6463  case AT_SetIdentity:
6464  return "ALTER COLUMN ... SET";
6465  case AT_DropIdentity:
6466  return "ALTER COLUMN ... DROP IDENTITY";
6467  case AT_ReAddStatistics:
6468  return NULL; /* not real grammar */
6469  }
6470 
6471  return NULL;
6472 }
@ AT_AddIndexConstraint
Definition: parsenodes.h:2362
@ AT_DropOf
Definition: parsenodes.h:2393
@ AT_CheckNotNull
Definition: parsenodes.h:2348
@ AT_SetOptions
Definition: parsenodes.h:2350
@ AT_DropIdentity
Definition: parsenodes.h:2405
@ AT_DisableTrigUser
Definition: parsenodes.h:2385
@ AT_DropNotNull
Definition: parsenodes.h:2344
@ AT_AddOf
Definition: parsenodes.h:2392
@ AT_ResetOptions
Definition: parsenodes.h:2351
@ AT_ReplicaIdentity
Definition: parsenodes.h:2394
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2377
@ AT_EnableRowSecurity
Definition: parsenodes.h:2395
@ AT_AddColumnToView
Definition: parsenodes.h:2341
@ AT_ResetRelOptions
Definition: parsenodes.h:2376
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2380
@ AT_DropOids
Definition: parsenodes.h:2372
@ AT_SetIdentity
Definition: parsenodes.h:2404
@ AT_ReAddStatistics
Definition: parsenodes.h:2406
@ AT_SetUnLogged
Definition: parsenodes.h:2371
@ AT_DisableTrig
Definition: parsenodes.h:2381
@ AT_SetCompression
Definition: parsenodes.h:2353
@ AT_DropExpression
Definition: parsenodes.h:2347
@ AT_AddIndex
Definition: parsenodes.h:2355
@ AT_EnableReplicaRule
Definition: parsenodes.h:2388
@ AT_ReAddIndex
Definition: parsenodes.h:2356
@ AT_DropConstraint
Definition: parsenodes.h:2363
@ AT_SetNotNull
Definition: parsenodes.h:2345
@ AT_ClusterOn
Definition: parsenodes.h:2368
@ AT_AddIdentity
Definition: parsenodes.h:2403
@ AT_ForceRowSecurity
Definition: parsenodes.h:2397
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2387
@ AT_SetAccessMethod
Definition: parsenodes.h:2373
@ AT_AlterColumnType
Definition: parsenodes.h:2365
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2402
@ AT_AddInherit
Definition: parsenodes.h:2390
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2359
@ AT_EnableTrig
Definition: parsenodes.h:2378
@ AT_DropColumn
Definition: parsenodes.h:2354
@ AT_ReAddComment
Definition: parsenodes.h:2364
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2366
@ AT_DisableTrigAll
Definition: parsenodes.h:2383
@ AT_EnableRule
Definition: parsenodes.h:2386
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2398
@ AT_DetachPartition
Definition: parsenodes.h:2401
@ AT_SetStatistics
Definition: parsenodes.h:2349
@ AT_AttachPartition
Definition: parsenodes.h:2400
@ AT_AddConstraint
Definition: parsenodes.h:2357
@ AT_DropInherit
Definition: parsenodes.h:2391
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2379
@ AT_SetLogged
Definition: parsenodes.h:2370
@ AT_SetStorage
Definition: parsenodes.h:2352
@ AT_DisableRule
Definition: parsenodes.h:2389
@ AT_DisableRowSecurity
Definition: parsenodes.h:2396
@ AT_SetRelOptions
Definition: parsenodes.h:2375
@ AT_ChangeOwner
Definition: parsenodes.h:2367
@ AT_EnableTrigUser
Definition: parsenodes.h:2384
@ AT_SetExpression
Definition: parsenodes.h:2346
@ AT_ReAddConstraint
Definition: parsenodes.h:2358
@ AT_SetTableSpace
Definition: parsenodes.h:2374
@ AT_GenericOptions
Definition: parsenodes.h:2399
@ AT_ColumnDefault
Definition: parsenodes.h:2342
@ AT_CookedColumnDefault
Definition: parsenodes.h:2343
@ AT_AlterConstraint
Definition: parsenodes.h:2360
@ AT_EnableTrigAll
Definition: parsenodes.h:2382
@ AT_DropCluster
Definition: parsenodes.h:2369
@ AT_ValidateConstraint
Definition: parsenodes.h:2361
@ AT_AddColumn
Definition: parsenodes.h:2340

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_CheckNotNull, AT_ClusterOn, AT_ColumnDefault, AT_CookedColumnDefault, AT_DetachPartition, AT_DetachPartitionFinalize, AT_DisableRowSecurity, AT_DisableRule, AT_DisableTrig, AT_DisableTrigAll, AT_DisableTrigUser, AT_DropCluster, AT_DropColumn, AT_DropConstraint, AT_DropExpression, AT_DropIdentity, AT_DropInherit, AT_DropNotNull, AT_DropOf, AT_DropOids, AT_EnableAlwaysRule, AT_EnableAlwaysTrig, AT_EnableReplicaRule, AT_EnableReplicaTrig, AT_EnableRowSecurity, AT_EnableRule, AT_EnableTrig, AT_EnableTrigAll, AT_EnableTrigUser, AT_ForceRowSecurity, AT_GenericOptions, AT_NoForceRowSecurity, AT_ReAddComment, AT_ReAddConstraint, AT_ReAddDomainConstraint, AT_ReAddIndex, AT_ReAddStatistics, AT_ReplaceRelOptions, AT_ReplicaIdentity, AT_ResetOptions, AT_ResetRelOptions, AT_SetAccessMethod, AT_SetCompression, AT_SetExpression, 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 17194 of file tablecmds.c.

17196 {
17197  List *indexList;
17198  ListCell *l;
17199 
17200  indexList = RelationGetIndexList(rel);
17201 
17202  foreach(l, indexList)
17203  {
17204  Oid indexOid = lfirst_oid(l);
17205  ObjectAddress thisobj;
17206 
17207  thisobj.classId = RelationRelationId;
17208  thisobj.objectId = indexOid;
17209  thisobj.objectSubId = 0;
17210 
17211  /*
17212  * Note: currently, the index will not have its own dependency on the
17213  * namespace, so we don't need to do changeDependencyFor(). There's no
17214  * row type in pg_type, either.
17215  *
17216  * XXX this objsMoved test may be pointless -- surely we have a single
17217  * dependency link from a relation to each index?
17218  */
17219  if (!object_address_present(&thisobj, objsMoved))
17220  {
17221  AlterRelationNamespaceInternal(classRel, indexOid,
17222  oldNspOid, newNspOid,
17223  false, objsMoved);
17224  add_exact_object_address(&thisobj, objsMoved);
17225  }
17226  }
17227 
17228  list_free(indexList);
17229 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2593
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2533
void list_free(List *list)
Definition: list.c:1546
#define lfirst_oid(lc)
Definition: pg_list.h:174
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4801
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17124

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

17128 {
17129  HeapTuple classTup;
17130  Form_pg_class classForm;
17131  ObjectAddress thisobj;
17132  bool already_done = false;
17133 
17134  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
17135  if (!HeapTupleIsValid(classTup))
17136  elog(ERROR, "cache lookup failed for relation %u", relOid);
17137  classForm = (Form_pg_class) GETSTRUCT(classTup);
17138 
17139  Assert(classForm->relnamespace == oldNspOid);
17140 
17141  thisobj.classId = RelationRelationId;
17142  thisobj.objectId = relOid;
17143  thisobj.objectSubId = 0;
17144 
17145  /*
17146  * If the object has already been moved, don't move it again. If it's
17147  * already in the right place, don't move it, but still fire the object
17148  * access hook.
17149  */
17150  already_done = object_address_present(&thisobj, objsMoved);
17151  if (!already_done && oldNspOid != newNspOid)
17152  {
17153  /* check for duplicate name (more friendly than unique-index failure) */
17154  if (get_relname_relid(NameStr(classForm->relname),
17155  newNspOid) != InvalidOid)
17156  ereport(ERROR,
17157  (errcode(ERRCODE_DUPLICATE_TABLE),
17158  errmsg("relation \"%s\" already exists in schema \"%s\"",
17159  NameStr(classForm->relname),
17160  get_namespace_name(newNspOid))));
17161 
17162  /* classTup is a copy, so OK to scribble on */
17163  classForm->relnamespace = newNspOid;
17164 
17165  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
17166 
17167  /* Update dependency on schema if caller said so */
17168  if (hasDependEntry &&
17169  changeDependencyFor(RelationRelationId,
17170  relOid,
17171  NamespaceRelationId,
17172  oldNspOid,
17173  newNspOid) != 1)
17174  elog(ERROR, "could not change schema dependency for relation \"%s\"",
17175  NameStr(classForm->relname));
17176  }
17177  if (!already_done)
17178  {
17179  add_exact_object_address(&thisobj, objsMoved);
17180 
17181  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
17182  }
17183 
17184  heap_freetuple(classTup);
17185 }
#define NameStr(name)
Definition: c.h:746
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#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:3366
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1885
#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:458
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86

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

17242 {
17243  Relation depRel;
17244  SysScanDesc scan;
17245  ScanKeyData key[2];
17246  HeapTuple tup;
17247 
17248  /*
17249  * SERIAL sequences are those having an auto dependency on one of the
17250  * table's columns (we don't care *which* column, exactly).
17251  */
17252  depRel = table_open(DependRelationId, AccessShareLock);
17253 
17254  ScanKeyInit(&key[0],
17255  Anum_pg_depend_refclassid,
17256  BTEqualStrategyNumber, F_OIDEQ,
17257  ObjectIdGetDatum(RelationRelationId));
17258  ScanKeyInit(&key[1],
17259  Anum_pg_depend_refobjid,
17260  BTEqualStrategyNumber, F_OIDEQ,
17262  /* we leave refobjsubid unspecified */
17263 
17264  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
17265  NULL, 2, key);
17266 
17267  while (HeapTupleIsValid(tup = systable_getnext(scan)))
17268  {
17269  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
17270  Relation seqRel;
17271 
17272  /* skip dependencies other than auto dependencies on columns */
17273  if (depForm->refobjsubid == 0 ||
17274  depForm->classid != RelationRelationId ||
17275  depForm->objsubid != 0 ||
17276  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
17277  continue;
17278 
17279  /* Use relation_open just in case it's an index */
17280  seqRel = relation_open(depForm->objid, lockmode);
17281 
17282  /* skip non-sequence relations */
17283  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
17284  {
17285  /* No need to keep the lock */
17286  relation_close(seqRel, lockmode);
17287  continue;
17288  }
17289 
17290  /* Fix the pg_class and pg_depend entries */
17291  AlterRelationNamespaceInternal(classRel, depForm->objid,
17292  oldNspOid, newNspOid,
17293  true, objsMoved);
17294 
17295  /*
17296  * Sequences used to have entries in pg_type, but no longer do. If we
17297  * ever re-instate that, we'll need to move the pg_type entry to the
17298  * new namespace, too (using AlterTypeNamespaceInternal).
17299  */
17300  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
17301 
17302  /* Now we can close it. Keep the lock till end of transaction. */
17303  relation_close(seqRel, NoLock);
17304  }
17305 
17306  systable_endscan(scan);
17307 
17309 }
@ DEPENDENCY_AUTO
Definition: dependency.h:34
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:597
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:504
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:385
#define AccessShareLock
Definition: lockdefs.h:36
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
#define RelationGetForm(relation)
Definition: rel.h:499
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:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
#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 4358 of file tablecmds.c.

4360 {
4361  Relation rel;
4362 
4363  /* Caller is required to provide an adequate lock. */
4364  rel = relation_open(context->relid, NoLock);
4365 
4366  CheckAlterTableIsSafe(rel);
4367 
4368  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4369 }
#define stmt
Definition: indent_codes.h:59
tree context
Definition: radixtree.h:1835
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4703

References ATController(), CheckAlterTableIsSafe(), context, NoLock, relation_open(), and stmt.

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4432 of file tablecmds.c.

4433 {
4434  /*
4435  * This only works if we read catalog tables using MVCC snapshots.
4436  */
4437  ListCell *lcmd;
4439 
4440  foreach(lcmd, cmds)
4441  {
4442  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4443  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4444 
4445  switch (cmd->subtype)
4446  {
4447  /*
4448  * These subcommands rewrite the heap, so require full locks.
4449  */
4450  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4451  * to SELECT */
4452  case AT_SetAccessMethod: /* must rewrite heap */
4453  case AT_SetTableSpace: /* must rewrite heap */
4454  case AT_AlterColumnType: /* must rewrite heap */
4455  cmd_lockmode = AccessExclusiveLock;
4456  break;
4457 
4458  /*
4459  * These subcommands may require addition of toast tables. If
4460  * we add a toast table to a table currently being scanned, we
4461  * might miss data added to the new toast table by concurrent
4462  * insert transactions.
4463  */
4464  case AT_SetStorage: /* may add toast tables, see
4465  * ATRewriteCatalogs() */
4466  cmd_lockmode = AccessExclusiveLock;
4467  break;
4468 
4469  /*
4470  * Removing constraints can affect SELECTs that have been
4471  * optimized assuming the constraint holds true. See also
4472  * CloneFkReferenced.
4473  */
4474  case AT_DropConstraint: /* as DROP INDEX */
4475  case AT_DropNotNull: /* may change some SQL plans */
4476  cmd_lockmode = AccessExclusiveLock;
4477  break;
4478 
4479  /*
4480  * Subcommands that may be visible to concurrent SELECTs
4481  */
4482  case AT_DropColumn: /* change visible to SELECT */
4483  case AT_AddColumnToView: /* CREATE VIEW */
4484  case AT_DropOids: /* used to equiv to DropColumn */
4485  case AT_EnableAlwaysRule: /* may change SELECT rules */
4486  case AT_EnableReplicaRule: /* may change SELECT rules */
4487  case AT_EnableRule: /* may change SELECT rules */
4488  case AT_DisableRule: /* may change SELECT rules */
4489  cmd_lockmode = AccessExclusiveLock;
4490  break;
4491 
4492  /*
4493  * Changing owner may remove implicit SELECT privileges
4494  */
4495  case AT_ChangeOwner: /* change visible to SELECT */
4496  cmd_lockmode = AccessExclusiveLock;
4497  break;
4498 
4499  /*
4500  * Changing foreign table options may affect optimization.
4501  */
4502  case AT_GenericOptions:
4504  cmd_lockmode = AccessExclusiveLock;
4505  break;
4506 
4507  /*
4508  * These subcommands affect write operations only.
4509  */
4510  case AT_EnableTrig:
4511  case AT_EnableAlwaysTrig:
4512  case AT_EnableReplicaTrig:
4513  case AT_EnableTrigAll:
4514  case AT_EnableTrigUser:
4515  case AT_DisableTrig:
4516  case AT_DisableTrigAll:
4517  case AT_DisableTrigUser:
4518  cmd_lockmode = ShareRowExclusiveLock;
4519  break;
4520 
4521  /*
4522  * These subcommands affect write operations only. XXX
4523  * Theoretically, these could be ShareRowExclusiveLock.
4524  */
4525  case AT_ColumnDefault:
4527  case AT_AlterConstraint:
4528  case AT_AddIndex: /* from ADD CONSTRAINT */
4529  case AT_AddIndexConstraint:
4530  case AT_ReplicaIdentity:
4531  case AT_SetNotNull:
4532  case AT_EnableRowSecurity:
4533  case AT_DisableRowSecurity:
4534  case AT_ForceRowSecurity:
4535  case AT_NoForceRowSecurity:
4536  case AT_AddIdentity:
4537  case AT_DropIdentity:
4538  case AT_SetIdentity:
4539  case AT_SetExpression:
4540  case AT_DropExpression:
4541  case AT_SetCompression:
4542  cmd_lockmode = AccessExclusiveLock;
4543  break;
4544 
4545  case AT_AddConstraint:
4546  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4547  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4548  if (IsA(cmd->def, Constraint))
4549  {
4550  Constraint *con = (Constraint *) cmd->def;
4551 
4552  switch (con->contype)
4553  {
4554  case CONSTR_EXCLUSION:
4555  case CONSTR_PRIMARY:
4556  case CONSTR_UNIQUE:
4557 
4558  /*
4559  * Cases essentially the same as CREATE INDEX. We
4560  * could reduce the lock strength to ShareLock if
4561  * we can work out how to allow concurrent catalog
4562  * updates. XXX Might be set down to
4563  * ShareRowExclusiveLock but requires further
4564  * analysis.
4565  */
4566  cmd_lockmode = AccessExclusiveLock;
4567  break;
4568  case CONSTR_FOREIGN:
4569 
4570  /*
4571  * We add triggers to both tables when we add a
4572  * Foreign Key, so the lock level must be at least
4573  * as strong as CREATE TRIGGER.
4574  */
4575  cmd_lockmode = ShareRowExclusiveLock;
4576  break;
4577 
4578  default:
4579  cmd_lockmode = AccessExclusiveLock;
4580  }
4581  }
4582  break;
4583 
4584  /*
4585  * These subcommands affect inheritance behaviour. Queries
4586  * started before us will continue to see the old inheritance
4587  * behaviour, while queries started after we commit will see
4588  * new behaviour. No need to prevent reads or writes to the
4589  * subtable while we hook it up though. Changing the TupDesc
4590  * may be a problem, so keep highest lock.
4591  */
4592  case AT_AddInherit:
4593  case AT_DropInherit:
4594  cmd_lockmode = AccessExclusiveLock;
4595  break;
4596 
4597  /*
4598  * These subcommands affect implicit row type conversion. They
4599  * have affects similar to CREATE/DROP CAST on queries. don't
4600  * provide for invalidating parse trees as a result of such
4601  * changes, so we keep these at AccessExclusiveLock.
4602  */
4603  case AT_AddOf:
4604  case AT_DropOf:
4605  cmd_lockmode = AccessExclusiveLock;
4606  break;
4607 
4608  /*
4609  * Only used by CREATE OR REPLACE VIEW which must conflict
4610  * with an SELECTs currently using the view.
4611  */
4612  case AT_ReplaceRelOptions:
4613  cmd_lockmode = AccessExclusiveLock;
4614  break;
4615 
4616  /*
4617  * These subcommands affect general strategies for performance
4618  * and maintenance, though don't change the semantic results
4619  * from normal data reads and writes. Delaying an ALTER TABLE
4620  * behind currently active writes only delays the point where
4621  * the new strategy begins to take effect, so there is no
4622  * benefit in waiting. In this case the minimum restriction
4623  * applies: we don't currently allow concurrent catalog
4624  * updates.
4625  */
4626  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4627  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4628  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4629  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4630  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4631  cmd_lockmode = ShareUpdateExclusiveLock;
4632  break;
4633 
4634  case AT_SetLogged:
4635  case AT_SetUnLogged:
4636  cmd_lockmode = AccessExclusiveLock;
4637  break;
4638 
4639  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4640  cmd_lockmode = ShareUpdateExclusiveLock;
4641  break;
4642 
4643  /*
4644  * Rel options are more complex than first appears. Options
4645  * are set here for tables, views and indexes; for historical
4646  * reasons these can all be used with ALTER TABLE, so we can't
4647  * decide between them using the basic grammar.
4648  */
4649  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4650  * getTables() */
4651  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4652  * getTables() */
4653  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4654  break;
4655 
4656  case AT_AttachPartition:
4657  cmd_lockmode = ShareUpdateExclusiveLock;
4658  break;
4659 
4660  case AT_DetachPartition:
4661  if (((PartitionCmd *) cmd->def)->concurrent)
4662  cmd_lockmode = ShareUpdateExclusiveLock;
4663  else
4664  cmd_lockmode = AccessExclusiveLock;
4665  break;
4666 
4668  cmd_lockmode = ShareUpdateExclusiveLock;
4669  break;
4670 
4671  case AT_CheckNotNull:
4672 
4673  /*
4674  * This only examines the table's schema; but lock must be
4675  * strong enough to prevent concurrent DROP NOT NULL.
4676  */
4677  cmd_lockmode = AccessShareLock;
4678  break;
4679 
4680  default: /* oops */
4681  elog(ERROR, "unrecognized alter table type: %d",
4682  (int) cmd->subtype);
4683  break;
4684  }
4685 
4686  /*
4687  * Take the greatest lockmode from any subcommand
4688  */
4689  if (cmd_lockmode > lockmode)
4690  lockmode = cmd_lockmode;
4691  }
4692 
4693  return lockmode;
4694 }
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:158
@ CONSTR_UNIQUE
Definition: parsenodes.h:2697
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2698
@ CONSTR_PRIMARY
Definition: parsenodes.h:2696
#define lfirst(lc)
Definition: pg_list.h:172
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2108
AlterTableType subtype
Definition: parsenodes.h:2419
ConstrType contype
Definition: parsenodes.h:2721

References AccessExclusiveLock, AccessShareLock, 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_CheckNotNull, AT_ClusterOn, AT_ColumnDefault, AT_CookedColumnDefault, AT_DetachPartition, AT_DetachPartitionFinalize, AT_DisableRowSecurity, AT_DisableRule, AT_DisableTrig, AT_DisableTrigAll, AT_DisableTrigUser, AT_DropCluster, AT_DropColumn, AT_DropConstraint, AT_DropExpression, AT_DropIdentity, AT_DropInherit, AT_DropNotNull, AT_DropOf, AT_DropOids, AT_EnableAlwaysRule, AT_EnableAlwaysTrig, AT_EnableReplicaRule, AT_EnableReplicaTrig, AT_EnableRowSecurity, AT_EnableRule, AT_EnableTrig, AT_EnableTrigAll, AT_EnableTrigUser, AT_ForceRowSecurity, AT_GenericOptions, AT_NoForceRowSecurity, AT_ReAddConstraint, AT_ReAddDomainConstraint, AT_ReplaceRelOptions, AT_ReplicaIdentity, AT_ResetOptions, AT_ResetRelOptions, AT_SetAccessMethod, AT_SetCompression, AT_SetExpression, 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 4387 of file tablecmds.c.

4388 {
4389  Relation rel;
4390  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4391 
4392  rel = relation_open(relid, lockmode);
4393 
4395 
4396  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4397 }
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4432

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4299 of file tablecmds.c.

4300 {
4301  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4302  stmt->missing_ok ? RVR_MISSING_OK : 0,
4304  (void *) stmt);
4305 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:426
@ RVR_MISSING_OK
Definition: namespace.h:72
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:17649

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

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 15191 of file tablecmds.c.

15192 {
15193  List *relations = NIL;
15194  ListCell *l;
15195  ScanKeyData key[1];
15196  Relation rel;
15197  TableScanDesc scan;
15198  HeapTuple tuple;
15199  Oid orig_tablespaceoid;
15200  Oid new_tablespaceoid;
15201  List *role_oids = roleSpecsToIds(stmt->roles);
15202 
15203  /* Ensure we were not asked to move something we can't */
15204  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
15205  stmt->objtype != OBJECT_MATVIEW)
15206  ereport(ERROR,
15207  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15208  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
15209 
15210  /* Get the orig and new tablespace OIDs */
15211  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
15212  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
15213 
15214  /* Can't move shared relations in to or out of pg_global */
15215  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
15216  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
15217  new_tablespaceoid == GLOBALTABLESPACE_OID)
15218  ereport(ERROR,
15219  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15220  errmsg("cannot move relations in to or out of pg_global tablespace")));
15221 
15222  /*
15223  * Must have CREATE rights on the new tablespace, unless it is the
15224  * database default tablespace (which all users implicitly have CREATE
15225  * rights on).
15226  */
15227  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
15228  {
15229  AclResult aclresult;
15230 
15231  aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
15232  ACL_CREATE);
15233  if (aclresult != ACLCHECK_OK)
15234  aclcheck_error(aclresult, OBJECT_TABLESPACE,
15235  get_tablespace_name(new_tablespaceoid));
15236  }
15237 
15238  /*
15239  * Now that the checks are done, check if we should set either to
15240  * InvalidOid because it is our database's default tablespace.
15241  */
15242  if (orig_tablespaceoid == MyDatabaseTableSpace)
15243  orig_tablespaceoid = InvalidOid;
15244 
15245  if (new_tablespaceoid == MyDatabaseTableSpace)
15246  new_tablespaceoid = InvalidOid;
15247 
15248  /* no-op */
15249  if (orig_tablespaceoid == new_tablespaceoid)
15250  return new_tablespaceoid;
15251 
15252  /*
15253  * Walk the list of objects in the tablespace and move them. This will
15254  * only find objects in our database, of course.
15255  */
15256  ScanKeyInit(&key[0],
15257  Anum_pg_class_reltablespace,
15258  BTEqualStrategyNumber, F_OIDEQ,
15259  ObjectIdGetDatum(orig_tablespaceoid));
15260 
15261  rel = table_open(RelationRelationId, AccessShareLock);
15262  scan = table_beginscan_catalog(rel, 1, key);
15263  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
15264  {
15265  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
15266  Oid relOid = relForm->oid;
15267 
15268  /*
15269  * Do not move objects in pg_catalog as part of this, if an admin
15270  * really wishes to do so, they can issue the individual ALTER
15271  * commands directly.
15272  *
15273  * Also, explicitly avoid any shared tables, temp tables, or TOAST
15274  * (TOAST will be moved with the main table).
15275  */
15276  if (IsCatalogNamespace(relForm->relnamespace) ||
15277  relForm->relisshared ||
15278  isAnyTempNamespace(relForm->relnamespace) ||
15279  IsToastNamespace(relForm->relnamespace))
15280  continue;
15281 
15282  /* Only move the object type requested */
15283  if ((stmt->objtype == OBJECT_TABLE &&
15284  relForm->relkind != RELKIND_RELATION &&
15285  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
15286  (stmt->objtype == OBJECT_INDEX &&
15287  relForm->relkind != RELKIND_INDEX &&
15288  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
15289  (stmt->objtype == OBJECT_MATVIEW &&
15290  relForm->relkind != RELKIND_MATVIEW))
15291  continue;
15292 
15293  /* Check if we are only moving objects owned by certain roles */
15294  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
15295  continue;
15296 
15297  /*
15298  * Handle permissions-checking here since we are locking the tables
15299  * and also to avoid doing a bunch of work only to fail part-way. Note
15300  * that permissions will also be checked by AlterTableInternal().
15301  *
15302  * Caller must be considered an owner on the table to move it.
15303  */
15304  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
15306  NameStr(relForm->relname));
15307 
15308  if (stmt->nowait &&
15310  ereport(ERROR,
15311  (errcode(ERRCODE_OBJECT_IN_USE),
15312  errmsg("aborting because lock on relation \"%s.%s\" is not available",
15313  get_namespace_name(relForm->relnamespace),
15314  NameStr(relForm->relname))));
15315  else
15317 
15318  /* Add to our list of objects to move */
15319  relations = lappend_oid(relations, relOid);
15320  }
15321 
15322  table_endscan(scan);
15324 
15325  if (relations == NIL)
15326  ereport(NOTICE,
15327  (errcode(ERRCODE_NO_DATA_FOUND),
15328  errmsg("no matching relations in tablespace \"%s\" found",
15329  orig_tablespaceoid == InvalidOid ? "(database default)" :
15330  get_tablespace_name(orig_tablespaceoid))));
15331 
15332  /* Everything is locked, loop through and move all of the relations. */
15333  foreach(l, relations)
15334  {
15335  List *cmds = NIL;
15337 
15338  cmd->subtype = AT_SetTableSpace;
15339  cmd->name = stmt->new_tablespacename;
15340 
15341  cmds = lappend(cmds, cmd);
15342 
15344  /* OID is set by AlterTableInternal */
15345  AlterTableInternal(lfirst_oid(l), cmds, false);
15347  }
15348 
15349  return new_tablespaceoid;
15350 }
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2700
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3888
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4142
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1426
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:221
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:203
#define NOTICE
Definition: elog.h:35
void EventTriggerAlterTableStart(Node *parsetree)
void EventTriggerAlterTableEnd(void)
Oid MyDatabaseTableSpace
Definition: globals.c:95
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1252
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:722
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:151
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2003
Oid GetUserId(void)
Definition: miscinit.c:514
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3672
#define makeNode(_type_)
Definition: nodes.h:155
ObjectType get_relkind_objtype(char relkind)
@ OBJECT_MATVIEW
Definition: parsenodes.h:2271
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2290
@ OBJECT_INDEX
Definition: parsenodes.h:2268
@ OBJECT_TABLE
Definition: parsenodes.h:2289
#define ACL_CREATE
Definition: parsenodes.h:85
@ 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:1019
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4387
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1652

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

17017 {
17018  Relation rel;
17019  Oid relid;
17020  Oid oldNspOid;
17021  Oid nspOid;
17022  RangeVar *newrv;
17023  ObjectAddresses *objsMoved;
17024  ObjectAddress myself;
17025 
17027  stmt->missing_ok ? RVR_MISSING_OK : 0,
17029  (void *) stmt);
17030 
17031  if (!OidIsValid(relid))
17032  {
17033  ereport(NOTICE,
17034  (errmsg("relation \"%s\" does not exist, skipping",
17035  stmt->relation->relname)));
17036  return InvalidObjectAddress;
17037  }
17038 
17039  rel = relation_open(relid, NoLock);
17040 
17041  oldNspOid = RelationGetNamespace(rel);
17042 
17043  /* If it's an owned sequence, disallow moving it by itself. */
17044  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
17045  {
17046  Oid tableId;
17047  int32 colId;
17048 
17049  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
17050  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
17051  ereport(ERROR,
17052  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17053  errmsg("cannot move an owned sequence into another schema"),
17054  errdetail("Sequence \"%s\" is linked to table \"%s\".",
17056  get_rel_name(tableId))));
17057  }
17058 
17059  /* Get and lock schema OID and check its permissions. */
17060  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
17061  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
17062 
17063  /* common checks on switching namespaces */
17064  CheckSetNamespace(oldNspOid, nspOid);
17065 
17066  objsMoved = new_object_addresses();
17067  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
17068  free_object_addresses(objsMoved);
17069 
17070  ObjectAddressSet(myself, RelationRelationId, relid);
17071 
17072  if (oldschema)
17073  *oldschema = oldNspOid;
17074 
17075  /* close rel, but keep lock until commit */
17076  relation_close(rel, NoLock);
17077 
17078  return myself;
17079 }
signed int int32
Definition: c.h:494
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2487
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2773
int errdetail(const char *fmt,...)
Definition: elog.c:1203
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:424
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:724
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3444
const ObjectAddress InvalidObjectAddress
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:829
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17087

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

17089 {
17090  Relation classRel;
17091 
17092  Assert(objsMoved != NULL);
17093 
17094  /* OK, modify the pg_class row and pg_depend entry */
17095  classRel = table_open(RelationRelationId, RowExclusiveLock);
17096 
17097  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
17098  nspOid, true, objsMoved);
17099 
17100  /* Fix the table's row type too, if it has one */
17101  if (OidIsValid(rel->rd_rel->reltype))
17102  AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid,
17103  false, /* isImplicitArray */
17104  false, /* ignoreDependent */
17105  false, /* errorOnTableType */
17106  objsMoved);
17107 
17108  /* Fix other dependent stuff */
17109  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
17110  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
17111  objsMoved, AccessExclusiveLock);
17112  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
17113  false, objsMoved);
17114 
17115  table_close(classRel, RowExclusiveLock);
17116 }
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:17239
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17194
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:4156

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

◆ ATAddCheckConstraint()

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

Definition at line 9386 of file tablecmds.c.

9389 {
9390  List *newcons;
9391  ListCell *lcon;
9392  List *children;
9393  ListCell *child;
9395 
9396  /* At top level, permission check was done in ATPrepCmd, else do it */
9397  if (recursing)
9399 
9400  /*
9401  * Call AddRelationNewConstraints to do the work, making sure it works on
9402  * a copy of the Constraint so transformExpr can't modify the original. It
9403  * returns a list of cooked constraints.
9404  *
9405  * If the constraint ends up getting merged with a pre-existing one, it's
9406  * omitted from the returned list, which is what we want: we do not need
9407  * to do any validation work. That can only happen at child tables,
9408  * though, since we disallow merging at the top level.
9409  */
9410  newcons = AddRelationNewConstraints(rel, NIL,
9411  list_make1(copyObject(constr)),
9412  recursing || is_readd, /* allow_merge */
9413  !recursing, /* is_local */
9414  is_readd, /* is_internal */
9415  NULL); /* queryString not available
9416  * here */
9417 
9418  /* we don't expect more than one constraint here */
9419  Assert(list_length(newcons) <= 1);
9420 
9421  /* Add each to-be-validated constraint to Phase 3's queue */
9422  foreach(lcon, newcons)
9423  {
9424  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
9425 
9426  if (!ccon->skip_validation)
9427  {
9428  NewConstraint *newcon;
9429 
9430  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9431  newcon->name = ccon->name;
9432  newcon->contype = ccon->contype;
9433  newcon->qual = ccon->expr;
9434 
9435  tab->constraints = lappend(tab->constraints, newcon);
9436  }
9437 
9438  /* Save the actually assigned name if it was defaulted */
9439  if (constr->conname == NULL)
9440  constr->conname = ccon->name;
9441 
9442  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
9443  }
9444 
9445  /* At this point we must have a locked-down name to use */
9446  Assert(constr->conname != NULL);
9447 
9448  /* Advance command counter in case same table is visited multiple times */
9450 
9451  /*
9452  * If the constraint got merged with an existing constraint, we're done.
9453  * We mustn't recurse to child tables in this case, because they've
9454  * already got the constraint, and visiting them again would lead to an
9455  * incorrect value for coninhcount.
9456  */
9457  if (newcons == NIL)
9458  return address;
9459 
9460  /*
9461  * If adding a NO INHERIT constraint, no need to find our children.
9462  */
9463  if (constr->is_no_inherit)
9464  return address;
9465 
9466  /*
9467  * Propagate to children as appropriate. Unlike most other ALTER
9468  * routines, we have to do this one level of recursion at a time; we can't
9469  * use find_all_inheritors to do it in one pass.
9470  */
9471  children =
9473 
9474  /*
9475  * Check if ONLY was specified with ALTER TABLE. If so, allow the
9476  * constraint creation only if there are no children currently. Error out
9477  * otherwise.
9478  */
9479  if (!recurse && children != NIL)
9480  ereport(ERROR,
9481  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9482  errmsg("constraint must be added to child tables too")));
9483 
9484  foreach(child, children)
9485  {
9486  Oid childrelid = lfirst_oid(child);
9487  Relation childrel;
9488  AlteredTableInfo *childtab;
9489 
9490  /* find_inheritance_children already got lock */
9491  childrel = table_open(childrelid, NoLock);
9492  CheckAlterTableIsSafe(childrel);
9493 
9494  /* Find or create work queue entry for this table */
9495  childtab = ATGetQueueEntry(wqueue, childrel);
9496 
9497  /* Recurse to child */
9498  ATAddCheckConstraint(wqueue, childtab, childrel,
9499  constr, recurse, true, is_readd, lockmode);
9500 
9501  table_close(childrel, NoLock);
9502  }
9503 
9504  return address;
9505 }
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2258
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:58
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:2727
Oid conoid
Definition: heap.h:38
char * name
Definition: heap.h:39
bool skip_validation
Definition: heap.h:42
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:41
#define ATT_TABLE
Definition: tablecmds.c:325
static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
Definition: tablecmds.c:6482
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:330
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:9386

References AddRelationNewConstraints(), Assert, AT_AddConstraint, ATGetQueueEntry(), ATSimplePermissions(), ATT_FOREIGN_TABLE, ATT_TABLE, CheckAlterTableIsSafe(), CommandCounterIncrement(), Constraint::conname, CookedConstraint::conoid, AlteredTableInfo::constraints, NewConstraint::contype, CookedConstraint::contype, copyObject, ereport, errcode(), errmsg(), ERROR, CookedConstraint::expr, find_inheritance_children(), InvalidObjectAddress, Constraint::is_no_inherit, lappend(), lfirst, lfirst_oid, list_length(), list_make1, NewConstraint::name, CookedConstraint::name, NIL, NoLock, ObjectAddressSet, palloc0(), NewConstraint::qual, RelationGetRelid, 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 9523 of file tablecmds.c.

9526 {
9527  Relation pkrel;
9528  int16 pkattnum[INDEX_MAX_KEYS] = {0};
9529  int16 fkattnum[INDEX_MAX_KEYS] = {0};
9530  Oid pktypoid[INDEX_MAX_KEYS] = {0};
9531  Oid fktypoid[INDEX_MAX_KEYS] = {0};
9532  Oid opclasses[INDEX_MAX_KEYS] = {0};
9533  Oid pfeqoperators[INDEX_MAX_KEYS] = {0};
9534  Oid ppeqoperators[INDEX_MAX_KEYS] = {0};
9535  Oid ffeqoperators[INDEX_MAX_KEYS] = {0};
9536  int16 fkdelsetcols[INDEX_MAX_KEYS] = {0};
9537  int i;
9538  int numfks,
9539  numpks,
9540  numfkdelsetcols;
9541  Oid indexOid;
9542  bool old_check_ok;
9543  ObjectAddress address;
9544  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
9545 
9546  /*
9547  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
9548  * delete rows out from under us.
9549  */
9550  if (OidIsValid(fkconstraint->old_pktable_oid))
9551  pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
9552  else
9553  pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
9554 
9555  /*
9556  * Validity checks (permission checks wait till we have the column
9557  * numbers)
9558  */
9559  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9560  {
9561  if (!recurse)
9562  ereport(ERROR,
9563  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9564  errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9566  RelationGetRelationName(pkrel))));
9567  if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
9568  ereport(ERROR,
9569  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9570  errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9572  RelationGetRelationName(pkrel)),
9573  errdetail("This feature is not yet supported on partitioned tables.")));
9574  }
9575 
9576  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9577  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9578  ereport(ERROR,
9579  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9580  errmsg("referenced relation \"%s\" is not a table",
9581  RelationGetRelationName(pkrel))));
9582 
9583  if (!allowSystemTableMods && IsSystemRelation(pkrel))
9584  ereport(ERROR,
9585  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
9586  errmsg("permission denied: \"%s\" is a system catalog",
9587  RelationGetRelationName(pkrel))));
9588 
9589  /*
9590  * References from permanent or unlogged tables to temp tables, and from
9591  * permanent tables to unlogged tables, are disallowed because the
9592  * referenced data can vanish out from under us. References from temp
9593  * tables to any other table type are also disallowed, because other
9594  * backends might need to run the RI triggers on the perm table, but they
9595  * can't reliably see tuples in the local buffers of other backends.
9596  */
9597  switch (rel->rd_rel->relpersistence)
9598  {
9599  case RELPERSISTENCE_PERMANENT:
9600  if (!RelationIsPermanent(pkrel))
9601  ereport(ERROR,
9602  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9603  errmsg("constraints on permanent tables may reference only permanent tables")));
9604  break;
9605  case RELPERSISTENCE_UNLOGGED:
9606  if (!RelationIsPermanent(pkrel)
9607  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
9608  ereport(ERROR,
9609  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9610  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
9611  break;
9612  case RELPERSISTENCE_TEMP:
9613  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
9614  ereport(ERROR,
9615  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9616  errmsg("constraints on temporary tables may reference only temporary tables")));
9617  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
9618  ereport(ERROR,
9619  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9620  errmsg("constraints on temporary tables must involve temporary tables of this session")));
9621  break;
9622  }
9623 
9624  /*
9625  * Look up the referencing attributes to make sure they exist, and record
9626  * their attnums and type OIDs.
9627  */
9629  fkconstraint->fk_attrs,
9630  fkattnum, fktypoid);
9631 
9632  numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel),
9633  fkconstraint->fk_del_set_cols,
9634  fkdelsetcols, NULL);
9635  validateFkOnDeleteSetColumns(numfks, fkattnum,
9636  numfkdelsetcols, fkdelsetcols,
9637  fkconstraint->fk_del_set_cols);
9638 
9639  /*
9640  * If the attribute list for the referenced table was omitted, lookup the
9641  * definition of the primary key and use it. Otherwise, validate the
9642  * supplied attribute list. In either case, discover the index OID and
9643  * index opclasses, and the attnums and type OIDs of the attributes.
9644  */
9645  if (fkconstraint->pk_attrs == NIL)
9646  {
9647  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
9648  &fkconstraint->pk_attrs,
9649  pkattnum, pktypoid,
9650  opclasses);
9651  }
9652  else
9653  {
9654  numpks = transformColumnNameList(RelationGetRelid(pkrel),
9655  fkconstraint->pk_attrs,
9656  pkattnum, pktypoid);
9657  /* Look for an index matching the column list */
9658  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
9659  opclasses);
9660  }
9661 
9662  /*
9663  * Now we can check permissions.
9664  */
9665  checkFkeyPermissions(pkrel, pkattnum, numpks);
9666 
9667  /*
9668  * Check some things for generated columns.
9669  */
9670  for (i = 0; i < numfks; i++)
9671  {
9672  char attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
9673 
9674  if (attgenerated)
9675  {
9676  /*
9677  * Check restrictions on UPDATE/DELETE actions, per SQL standard
9678  */
9679  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
9680  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
9681  fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
9682  ereport(ERROR,
9683  (errcode(ERRCODE_SYNTAX_ERROR),
9684  errmsg("invalid %s action for foreign key constraint containing generated column",
9685  "ON UPDATE")));
9686  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
9687  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
9688  ereport(ERROR,
9689  (errcode(ERRCODE_SYNTAX_ERROR),
9690  errmsg("invalid %s action for foreign key constraint containing generated column",
9691  "ON DELETE")));
9692  }
9693  }
9694 
9695  /*
9696  * Look up the equality operators to use in the constraint.
9697  *
9698  * Note that we have to be careful about the difference between the actual
9699  * PK column type and the opclass' declared input type, which might be
9700  * only binary-compatible with it. The declared opcintype is the right
9701  * thing to probe pg_amop with.
9702  */
9703  if (numfks != numpks)
9704  ereport(ERROR,
9705  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
9706  errmsg("number of referencing and referenced columns for foreign key disagree")));
9707 
9708  /*
9709  * On the strength of a previous constraint, we might avoid scanning
9710  * tables to validate this one. See below.
9711  */
9712  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
9713  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
9714 
9715  for (i = 0; i < numpks; i++)
9716  {
9717  Oid pktype = pktypoid[i];
9718  Oid fktype = fktypoid[i];
9719  Oid fktyped;
9720  HeapTuple cla_ht;
9721  Form_pg_opclass cla_tup;
9722  Oid amid;
9723  Oid opfamily;
9724  Oid opcintype;
9725  Oid pfeqop;
9726  Oid ppeqop;
9727  Oid ffeqop;
9728  int16 eqstrategy;
9729  Oid pfeqop_right;
9730 
9731  /* We need several fields out of the pg_opclass entry */
9732  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
9733  if (!HeapTupleIsValid(cla_ht))
9734  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
9735  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
9736  amid = cla_tup->opcmethod;
9737  opfamily = cla_tup->opcfamily;
9738  opcintype = cla_tup->opcintype;
9739  ReleaseSysCache(cla_ht);
9740 
9741  /*
9742  * Check it's a btree; currently this can never fail since no other
9743  * index AMs support unique indexes. If we ever did have other types
9744  * of unique indexes, we'd need a way to determine which operator
9745  * strategy number is equality. (Is it reasonable to insist that
9746  * every such index AM use btree's number for equality?)
9747  */
9748  if (amid != BTREE_AM_OID)
9749  elog(ERROR, "only b-tree indexes are supported for foreign keys");
9750  eqstrategy = BTEqualStrategyNumber;
9751 
9752  /*
9753  * There had better be a primary equality operator for the index.
9754  * We'll use it for PK = PK comparisons.
9755  */
9756  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
9757  eqstrategy);
9758 
9759  if (!OidIsValid(ppeqop))
9760  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
9761  eqstrategy, opcintype, opcintype, opfamily);
9762 
9763  /*
9764  * Are there equality operators that take exactly the FK type? Assume
9765  * we should look through any domain here.
9766  */
9767  fktyped = getBaseType(fktype);
9768 
9769  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
9770  eqstrategy);
9771  if (OidIsValid(pfeqop))
9772  {
9773  pfeqop_right = fktyped;
9774  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
9775  eqstrategy);
9776  }
9777  else
9778  {
9779  /* keep compiler quiet */
9780  pfeqop_right = InvalidOid;
9781  ffeqop = InvalidOid;
9782  }
9783 
9784  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9785  {
9786  /*
9787  * Otherwise, look for an implicit cast from the FK type to the
9788  * opcintype, and if found, use the primary equality operator.
9789  * This is a bit tricky because opcintype might be a polymorphic
9790  * type such as ANYARRAY or ANYENUM; so what we have to test is
9791  * whether the two actual column types can be concurrently cast to
9792  * that type. (Otherwise, we'd fail to reject combinations such
9793  * as int[] and point[].)
9794  */
9795  Oid input_typeids[2];
9796  Oid target_typeids[2];
9797 
9798  input_typeids[0] = pktype;
9799  input_typeids[1] = fktype;
9800  target_typeids[0] = opcintype;
9801  target_typeids[1] = opcintype;
9802  if (can_coerce_type(2, input_typeids, target_typeids,
9804  {
9805  pfeqop = ffeqop = ppeqop;
9806  pfeqop_right = opcintype;
9807  }
9808  }
9809 
9810  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9811  ereport(ERROR,
9812  (errcode(ERRCODE_DATATYPE_MISMATCH),
9813  errmsg("foreign key constraint \"%s\" cannot be implemented",
9814  fkconstraint->conname),
9815  errdetail("Key columns \"%s\" and \"%s\" "
9816  "are of incompatible types: %s and %s.",
9817  strVal(list_nth(fkconstraint->fk_attrs, i)),
9818  strVal(list_nth(fkconstraint->pk_attrs, i)),
9819  format_type_be(fktype),
9820  format_type_be(pktype))));
9821 
9822  if (old_check_ok)
9823  {
9824  /*
9825  * When a pfeqop changes, revalidate the constraint. We could
9826  * permit intra-opfamily changes, but that adds subtle complexity
9827  * without any concrete benefit for core types. We need not
9828  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
9829  */
9830  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
9831  old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
9832  old_pfeqop_item);
9833  }
9834  if (old_check_ok)
9835  {
9836  Oid old_fktype;
9837  Oid new_fktype;
9838  CoercionPathType old_pathtype;
9839  CoercionPathType new_pathtype;
9840  Oid old_castfunc;
9841  Oid new_castfunc;
9843  fkattnum[i] - 1);
9844 
9845  /*
9846  * Identify coercion pathways from each of the old and new FK-side
9847  * column types to the right (foreign) operand type of the pfeqop.
9848  * We may assume that pg_constraint.conkey is not changing.
9849  */
9850  old_fktype = attr->atttypid;
9851  new_fktype = fktype;
9852  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
9853  &old_castfunc);
9854  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
9855  &new_castfunc);
9856 
9857  /*
9858  * Upon a change to the cast from the FK column to its pfeqop
9859  * operand, revalidate the constraint. For this evaluation, a
9860  * binary coercion cast is equivalent to no cast at all. While
9861  * type implementors should design implicit casts with an eye
9862  * toward consistency of operations like equality, we cannot
9863  * assume here that they have done so.
9864  *
9865  * A function with a polymorphic argument could change behavior
9866  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
9867  * when the cast destination is polymorphic, we only avoid
9868  * revalidation if the input type has not changed at all. Given
9869  * just the core data types and operator classes, this requirement
9870  * prevents no would-be optimizations.
9871  *
9872  * If the cast converts from a base type to a domain thereon, then
9873  * that domain type must be the opcintype of the unique index.
9874  * Necessarily, the primary key column must then be of the domain
9875  * type. Since the constraint was previously valid, all values on
9876  * the foreign side necessarily exist on the primary side and in
9877  * turn conform to the domain. Consequently, we need not treat
9878  * domains specially here.
9879  *
9880  * Since we require that all collations share the same notion of
9881  * equality (which they do, because texteq reduces to bitwise
9882  * equality), we don't compare collation here.
9883  *
9884  * We need not directly consider the PK type. It's necessarily
9885  * binary coercible to the opcintype of the unique index column,
9886  * and ri_triggers.c will only deal with PK datums in terms of
9887  * that opcintype. Changing the opcintype also changes pfeqop.
9888  */
9889  old_check_ok = (new_pathtype == old_pathtype &&
9890  new_castfunc == old_castfunc &&
9891  (!IsPolymorphicType(pfeqop_right) ||
9892  new_fktype == old_fktype));
9893  }
9894 
9895  pfeqoperators[i] = pfeqop;
9896  ppeqoperators[i] = ppeqop;
9897  ffeqoperators[i] = ffeqop;
9898  }
9899 
9900  /*
9901  * Create all the constraint and trigger objects, recursing to partitions
9902  * as necessary. First handle the referenced side.
9903  */
9904  address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
9905  indexOid,
9906  InvalidOid, /* no parent constraint */
9907  numfks,
9908  pkattnum,
9909  fkattnum,
9910  pfeqoperators,
9911  ppeqoperators,
9912  ffeqoperators,
9913  numfkdelsetcols,
9914  fkdelsetcols,
9915  old_check_ok,
9917 
9918  /* Now handle the referencing side. */
9919  addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
9920  indexOid,
9921  address.objectId,
9922  numfks,
9923  pkattnum,
9924  fkattnum,
9925  pfeqoperators,
9926  ppeqoperators,
9927  ffeqoperators,
9928  numfkdelsetcols,
9929  fkdelsetcols,
9930  old_check_ok,
9931  lockmode,
9933 
9934  /*
9935  * Done. Close pk table, but keep lock until we've committed.
9936  */
9937  table_close(pkrel, NoLock);
9938 
9939  return address;
9940 }
signed short int16
Definition: c.h:493
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
bool allowSystemTableMods
Definition: globals.c:129
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:166
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2521
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:2711
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2709
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2710
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:714
#define RelationIsPermanent(relation)
Definition: rel.h:617
TupleDesc oldDesc
Definition: tablecmds.c:171
List * pk_attrs
Definition: parsenodes.h:2753
List * fk_del_set_cols
Definition: parsenodes.h:2757
Oid old_pktable_oid
Definition: parsenodes.h:2759
List * old_conpfeqop
Definition: parsenodes.h:2758
RangeVar * pktable
Definition: parsenodes.h:2751
bool rd_islocaltemp
Definition: rel.h:61
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
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:11775
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:12013
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids)
Definition: tablecmds.c:11723
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:12042
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
Definition: tablecmds.c:11874
static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, int numfksetcols, const int16 *fksetcolsattnums, List *fksetcols)
Definition: tablecmds.c:9948
#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(), 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 6602 of file tablecmds.c.

6603 {
6604  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6605  {
6606  List *inh;
6607  ListCell *cell;
6608 
6609  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6610  /* first element is the parent rel; must ignore it */
6611  for_each_from(cell, inh, 1)
6612  {
6613  Relation childrel;
6614 
6615  /* find_all_inheritors already got lock */
6616  childrel = table_open(lfirst_oid(cell), NoLock);
6617  CheckAlterTableIsSafe(childrel);
6618  table_close(childrel, NoLock);
6619  }
6620  list_free(inh);
6621  }
6622 }
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
#define for_each_from(cell, lst, N)
Definition: pg_list.h:414

References CheckAlterTableIsSafe(), 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 12929 of file tablecmds.c.

12930 {
12931  Assert(expr != NULL);
12932 
12933  for (;;)
12934  {
12935  /* only one varno, so no need to check that */
12936  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
12937  return false;
12938  else if (IsA(expr, RelabelType))
12939  expr = (Node *) ((RelabelType *) expr)->arg;
12940  else if (IsA(expr, CoerceToDomain))
12941  {
12942  CoerceToDomain *d = (CoerceToDomain *) expr;
12943 
12945  return true;
12946  expr = (Node *) d->arg;
12947  }
12948  else if (IsA(expr, FuncExpr))
12949  {
12950  FuncExpr *f = (FuncExpr *) expr;
12951 
12952  switch (f->funcid)
12953  {
12954  case F_TIMESTAMPTZ_TIMESTAMP:
12955  case F_TIMESTAMP_TIMESTAMPTZ:
12957  return true;
12958  else
12959  expr = linitial(f->args);
12960  break;
12961  default:
12962  return true;
12963  }
12964  }
12965  else
12966  return true;
12967  }
12968 }
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:6270
void * arg
#define linitial(l)
Definition: pg_list.h:178
Oid funcid
Definition: primnodes.h:750
List * args
Definition: primnodes.h:768
Definition: primnodes.h:248
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1417

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

4706 {
4707  List *wqueue = NIL;
4708  ListCell *lcmd;
4709 
4710  /* Phase 1: preliminary examination of commands, create work queue */
4711  foreach(lcmd, cmds)
4712  {
4713  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4714 
4715  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4716  }
4717 
4718  /* Close the relation, but keep lock until commit */
4719  relation_close(rel, NoLock);
4720 
4721  /* Phase 2: update system catalogs */
4722  ATRewriteCatalogs(&wqueue, lockmode, context);
4723 
4724  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4725  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4726 }
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5097
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4738
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5641

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

Referenced by AlterTable(), and AlterTableInternal().

◆ ATDetachCheckNoForeignKeyRefs()

static void ATDetachCheckNoForeignKeyRefs ( Relation  partition)
static

Definition at line 19897 of file tablecmds.c.

19898 {
19899  List *constraints;
19900  ListCell *cell;
19901 
19902  constraints = GetParentedForeignKeyRefs(partition);
19903 
19904  foreach(cell, constraints)
19905  {
19906  Oid constrOid = lfirst_oid(cell);
19907  HeapTuple tuple;
19908  Form_pg_constraint constrForm;
19909  Relation rel;
19910  Trigger trig = {0};
19911 
19912  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
19913  if (!HeapTupleIsValid(tuple))
19914  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
19915  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
19916 
19917  Assert(OidIsValid(constrForm->conparentid));
19918  Assert(constrForm->confrelid == RelationGetRelid(partition));
19919 
19920  /* prevent data changes into the referencing table until commit */
19921  rel = table_open(constrForm->conrelid, ShareLock);
19922 
19923  trig.tgoid = InvalidOid;
19924  trig.tgname = NameStr(constrForm->conname);
19926  trig.tgisinternal = true;
19927  trig.tgconstrrelid = RelationGetRelid(partition);
19928  trig.tgconstrindid = constrForm->conindid;
19929  trig.tgconstraint = constrForm->oid;
19930  trig.tgdeferrable = false;
19931  trig.tginitdeferred = false;
19932  /* we needn't fill in remaining fields */
19933 
19934  RI_PartitionRemove_Check(&trig, rel, partition);
19935 
19936  ReleaseSysCache(tuple);
19937 
19938  table_close(rel, NoLock);
19939  }
19940 }
#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:1654
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
static List * GetParentedForeignKeyRefs(Relation partition)
Definition: tablecmds.c:19844
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:149

References Assert, 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 17522 of file tablecmds.c.

17524 {
17525  ListCell *cur_item;
17526 
17527  foreach(cur_item, on_commits)
17528  {
17529  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
17530 
17531  if (!isCommit && oc->creating_subid == mySubid)
17532  {
17533  /* cur_item must be removed */
17535  pfree(oc);
17536  }
17537  else
17538  {
17539  /* cur_item must be preserved */
17540  if (oc->creating_subid == mySubid)
17541  oc->creating_subid = parentSubid;
17542  if (oc->deleting_subid == mySubid)
17543  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
17544  }
17545  }
17546 }
#define InvalidSubTransactionId
Definition: c.h:658
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
SubTransactionId creating_subid
Definition: tablecmds.c:125
SubTransactionId deleting_subid
Definition: tablecmds.c:126
static List * on_commits
Definition: tablecmds.c:129

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

17491 {
17492  ListCell *cur_item;
17493 
17494  foreach(cur_item, on_commits)
17495  {
17496  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
17497 
17498  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
17500  {
17501  /* cur_item must be removed */
17503  pfree(oc);
17504  }
17505  else
17506  {
17507  /* cur_item must be preserved */
17510  }
17511  }
17512 }

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,
AlterTablePass  cur_pass,
AlterTableUtilityContext context 
)
static

Definition at line 6958 of file tablecmds.c.

6962 {
6963  Oid myrelid = RelationGetRelid(rel);
6964  ColumnDef *colDef = castNode(ColumnDef, (*cmd)->def);
6965  bool if_not_exists = (*cmd)->missing_ok;
6966  Relation pgclass,
6967  attrdesc;
6968  HeapTuple reltup;
6969  Form_pg_class relform;
6970  Form_pg_attribute attribute;
6971  int newattnum;
6972  char relkind;
6973  Expr *defval;
6974  List *children;
6975  ListCell *child;
6976  AlterTableCmd *childcmd;
6977  ObjectAddress address;
6978  TupleDesc tupdesc;
6979 
6980  /* since this function recurses, it could be driven to stack overflow */
6982 
6983  /* At top level, permission check was done in ATPrepCmd, else do it */
6984  if (recursing)
6985  ATSimplePermissions((*cmd)->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
6986 
6987  if (rel->rd_rel->relispartition && !recursing)
6988  ereport(ERROR,
6989  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6990  errmsg("cannot add column to a partition")));
6991 
6992  attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
6993 
6994  /*
6995  * Are we adding the column to a recursion child? If so, check whether to
6996  * merge with an existing definition for the column. If we do merge, we
6997  * must not recurse. Children will already have the column, and recursing
6998  * into them would mess up attinhcount.
6999  */
7000  if (colDef->inhcount > 0)
7001  {
7002  HeapTuple tuple;
7003 
7004  /* Does child already have a column by this name? */
7005  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
7006  if (HeapTupleIsValid(tuple))
7007  {
7008  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
7009  Oid ctypeId;
7010  int32 ctypmod;
7011  Oid ccollid;
7012 
7013  /* Child column must match on type, typmod, and collation */
7014  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
7015  if (ctypeId != childatt->atttypid ||
7016  ctypmod != childatt->atttypmod)
7017  ereport(ERROR,
7018  (errcode(ERRCODE_DATATYPE_MISMATCH),
7019  errmsg("child table \"%s\" has different type for column \"%s\"",
7020  RelationGetRelationName(rel), colDef->colname)));
7021  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
7022  if (ccollid != childatt->attcollation)
7023  ereport(ERROR,
7024  (errcode(ERRCODE_COLLATION_MISMATCH),
7025  errmsg("child table \"%s\" has different collation for column \"%s\"",
7026  RelationGetRelationName(rel), colDef->colname),
7027  errdetail("\"%s\" versus \"%s\"",
7028  get_collation_name(ccollid),
7029  get_collation_name(childatt->attcollation))));
7030 
7031  /* Bump the existing child att's inhcount */
7032  childatt->attinhcount++;
7033  if (childatt->attinhcount < 0)
7034  ereport(ERROR,
7035  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
7036  errmsg("too many inheritance parents"));
7037  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
7038 
7039  heap_freetuple(tuple);
7040 
7041  /* Inform the user about the merge */
7042  ereport(NOTICE,
7043  (errmsg("merging definition of column \"%s\" for child \"%s\"",
7044  colDef->colname, RelationGetRelationName(rel))));
7045 
7046  table_close(attrdesc, RowExclusiveLock);
7047 
7048  /* Make the child column change visible */
7050 
7051  return InvalidObjectAddress;
7052  }
7053  }
7054 
7055  /* skip if the name already exists and if_not_exists is true */
7056  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
7057  {
7058  table_close(attrdesc, RowExclusiveLock);
7059  return InvalidObjectAddress;
7060  }
7061 
7062  /*
7063  * Okay, we need to add the column, so go ahead and do parse
7064  * transformation. This can result in queueing up, or even immediately
7065  * executing, subsidiary operations (such as creation of unique indexes);
7066  * so we mustn't do it until we have made the if_not_exists check.
7067  *
7068  * When recursing, the command was already transformed and we needn't do
7069  * so again. Also, if context isn't given we can't transform. (That
7070  * currently happens only for AT_AddColumnToView; we expect that view.c
7071  * passed us a ColumnDef that doesn't need work.)
7072  */
7073  if (context != NULL && !recursing)
7074  {
7075  *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
7076  cur_pass, context);
7077  Assert(*cmd != NULL);
7078  colDef = castNode(ColumnDef, (*cmd)->def);
7079  }
7080 
7081  /*
7082  * Regular inheritance children are independent enough not to inherit the
7083  * identity column from parent hence cannot recursively add identity
7084  * column if the table has inheritance children.
7085  *
7086  * Partitions, on the other hand, are integral part of a partitioned table
7087  * and inherit identity column. Hence propagate identity column down the
7088  * partition hierarchy.
7089  */
7090  if (colDef->identity &&
7091  recurse &&
7092  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE &&
7093  find_inheritance_children(myrelid, NoLock) != NIL)
7094  ereport(ERROR,
7095  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7096  errmsg("cannot recursively add identity column to table that has child tables")));
7097 
7098  pgclass = table_open(RelationRelationId, RowExclusiveLock);
7099 
7100  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
7101  if (!HeapTupleIsValid(reltup))
7102  elog(ERROR, "cache lookup failed for relation %u", myrelid);
7103  relform = (Form_pg_class) GETSTRUCT(reltup);
7104  relkind = relform->relkind;
7105 
7106  /* Determine the new attribute's number */
7107  newattnum = relform->relnatts + 1;
7108  if (newattnum > MaxHeapAttributeNumber)
7109  ereport(ERROR,
7110  (errcode(ERRCODE_TOO_MANY_COLUMNS),
7111  errmsg("tables can have at most %d columns",
7113 
7114  /*
7115  * Construct new attribute's pg_attribute entry.
7116  */
7117  tupdesc = BuildDescForRelation(list_make1(colDef));
7118 
7119  attribute = TupleDescAttr(tupdesc, 0);
7120 
7121  /* Fix up attribute number */
7122  attribute->attnum = newattnum;
7123 
7124  /* make sure datatype is legal for a column */
7125  CheckAttributeType(NameStr(attribute->attname), attribute->atttypid, attribute->attcollation,
7126  list_make1_oid(rel->rd_rel->reltype),
7127  0);
7128 
7129  InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
7130 
7131  table_close(attrdesc, RowExclusiveLock);
7132 
7133  /*
7134  * Update pg_class tuple as appropriate
7135  */
7136  relform->relnatts = newattnum;
7137 
7138  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
7139 
7140  heap_freetuple(reltup);
7141 
7142  /* Post creation hook for new attribute */
7143  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
7144 
7145  table_close(pgclass, RowExclusiveLock);
7146 
7147  /* Make the attribute's catalog entry visible */
7149 
7150  /*
7151  * Store the DEFAULT, if any, in the catalogs
7152  */
7153  if (colDef->raw_default)
7154  {
7155  RawColumnDefault *rawEnt;
7156 
7157  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
7158  rawEnt->attnum = attribute->attnum;
7159  rawEnt->raw_default = copyObject(colDef->raw_default);
7160 
7161  /*
7162  * Attempt to skip a complete table rewrite by storing the specified
7163  * DEFAULT value outside of the heap. This may be disabled inside
7164  * AddRelationNewConstraints if the optimization cannot be applied.
7165  */
7166  rawEnt->missingMode = (!colDef->generated);
7167 
7168  rawEnt->generated = colDef->generated;
7169 
7170  /*
7171  * This function is intended for CREATE TABLE, so it processes a
7172  * _list_ of defaults, but we just do one.
7173  */
7175  false, true, false, NULL);
7176 
7177  /* Make the additional catalog changes visible */
7179 
7180  /*
7181  * Did the request for a missing value work? If not we'll have to do a
7182  * rewrite
7183  */
7184  if (!rawEnt->missingMode)
7186  }
7187 
7188  /*
7189  * Tell Phase 3 to fill in the default expression, if there is one.
7190  *
7191  * If there is no default, Phase 3 doesn't have to do anything, because
7192  * that effectively means that the default is NULL. The heap tuple access
7193  * routines always check for attnum > # of attributes in tuple, and return
7194  * NULL if so, so without any modification of the tuple data we will get
7195  * the effect of NULL values in the new column.
7196  *
7197  * An exception occurs when the new column is of a domain type: the domain
7198  * might have a not-null constraint, or a check constraint that indirectly
7199  * rejects nulls. If there are any domain constraints then we construct
7200  * an explicit NULL default value that will be passed through
7201  * CoerceToDomain processing. (This is a tad inefficient, since it causes
7202  * rewriting the table which we really don't have to do, but the present
7203  * design of domain processing doesn't offer any simple way of checking
7204  * the constraints more directly.)
7205  *
7206  * Note: we use build_column_default, and not just the cooked default
7207  * returned by AddRelationNewConstraints, so that the right thing happens
7208  * when a datatype's default applies.
7209  *
7210  * Note: it might seem that this should happen at the end of Phase 2, so
7211  * that the effects of subsequent subcommands can be taken into account.
7212  * It's intentional that we do it now, though. The new column should be
7213  * filled according to what is said in the ADD COLUMN subcommand, so that
7214  * the effects are the same as if this subcommand had been run by itself
7215  * and the later subcommands had been issued in new ALTER TABLE commands.
7216  *
7217  * We can skip this entirely for relations without storage, since Phase 3
7218  * is certainly not going to touch them. System attributes don't have
7219  * interesting defaults, either.
7220  */
7221  if (RELKIND_HAS_STORAGE(relkind))
7222  {
7223  /*
7224  * For an identity column, we can't use build_column_default(),
7225  * because the sequence ownership isn't set yet. So do it manually.
7226  */
7227  if (colDef->identity)
7228  {
7230 
7231  nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
7232  nve->typeId = attribute->atttypid;
7233 
7234  defval = (Expr *) nve;
7235 
7236  /* must do a rewrite for identity columns */
7238  }
7239  else
7240  defval = (Expr *) build_column_default(rel, attribute->attnum);
7241 
7242  if (!defval && DomainHasConstraints(attribute->atttypid))
7243  {
7244  Oid baseTypeId;
7245  int32 baseTypeMod;
7246  Oid baseTypeColl;
7247 
7248  baseTypeMod = attribute->atttypmod;
7249  baseTypeId = getBaseTypeAndTypmod(attribute->atttypid, &baseTypeMod);
7250  baseTypeColl = get_typcollation(baseTypeId);
7251  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
7252  defval = (Expr *) coerce_to_target_type(NULL,
7253  (Node *) defval,
7254  baseTypeId,
7255  attribute->atttypid,
7256  attribute->atttypmod,
7259  -1);
7260  if (defval == NULL) /* should not happen */
7261  elog(ERROR, "failed to coerce base type to domain");
7262  }
7263 
7264  if (defval)
7265  {
7267 
7269  newval->attnum = attribute->attnum;
7270  newval->expr = expression_planner(defval);
7271  newval->is_generated = (colDef->generated != '\0');
7272 
7273  tab->newvals = lappend(tab->newvals, newval);
7274  }
7275 
7276  if (DomainHasConstraints(attribute->atttypid))
7278 
7279  if (!TupleDescAttr(rel->rd_att, attribute->attnum - 1)->atthasmissing)
7280  {
7281  /*
7282  * If the new column is NOT NULL, and there is no missing value,
7283  * tell Phase 3 it needs to check for NULLs.
7284  */
7285  tab->verify_new_notnull |= colDef->is_not_null;
7286  }
7287  }
7288 
7289  /*
7290  * Add needed dependency entries for the new column.
7291  */
7292  add_column_datatype_dependency(myrelid, newattnum, attribute->atttypid);
7293  add_column_collation_dependency(myrelid, newattnum, attribute->attcollation);
7294 
7295  /*
7296  * Propagate to children as appropriate. Unlike most other ALTER
7297  * routines, we have to do this one level of recursion at a time; we can't
7298  * use find_all_inheritors to do it in one pass.
7299  */
7300  children =
7302 
7303  /*
7304  * If we are told not to recurse, there had better not be any child
7305  * tables; else the addition would put them out of step.
7306  */
7307  if (children && !recurse)
7308  ereport(ERROR,
7309  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7310  errmsg("column must be added to child tables too")));
7311 
7312  /* Children should see column as singly inherited */
7313  if (!recursing)
7314  {
7315  childcmd = copyObject(*cmd);
7316  colDef = castNode(ColumnDef, childcmd->def);
7317  colDef->inhcount = 1;
7318  colDef->is_local = false;
7319  }
7320  else
7321  childcmd = *cmd; /* no need to copy again */
7322 
7323  foreach(child, children)
7324  {
7325  Oid childrelid = lfirst_oid(child);
7326  Relation childrel;
7327  AlteredTableInfo *childtab;
7328 
7329  /* find_inheritance_children already got lock */
7330  childrel = table_open(childrelid, NoLock);
7331  CheckAlterTableIsSafe(childrel);
7332 
7333  /* Find or create work queue entry for this table */
7334  childtab = ATGetQueueEntry(wqueue, childrel);
7335 
7336  /* Recurse to child; return value is ignored */
7337  ATExecAddColumn(wqueue, childtab, childrel,
7338  &childcmd, recurse, true,
7339  lockmode, cur_pass, context);
7340 
7341  table_close(childrel, NoLock);
7342  }
7343 
7344  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
7345  return address;
7346 }
#define AT_REWRITE_DEFAULT_VAL
Definition: event_trigger.h:35
#define newval
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
Definition: heap.c:548
void InsertPgAttributeTuples(Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, const FormExtraData_pg_attribute tupdesc_extra[], CatalogIndexState indstate)
Definition: heap.c:702
#define MaxHeapAttributeNumber
Definition: htup_details.h:48
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3056
char * get_collation_name(Oid colloid)
Definition: lsyscache.c:1035
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2538
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:339
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:80
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
#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, const ColumnDef *coldef, Oid typeOid)
Definition: parse_type.c:540
#define list_make1_oid(x1)
Definition: pg_list.h:242
Expr * expression_planner(Expr *expr)
Definition: planner.c:6586
void check_stack_depth(void)
Definition: postgres.c:3540
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:736
@ COERCION_ASSIGNMENT
Definition: primnodes.h:715
Node * build_column_default(Relation rel, int attrno)
bool verify_new_notnull
Definition: tablecmds.c:188
bool is_not_null
Definition: parsenodes.h:731
char identity
Definition: parsenodes.h:737
RangeVar * identitySequence
Definition: parsenodes.h:738
int inhcount
Definition: parsenodes.h:729
char * colname
Definition: parsenodes.h:726
TypeName * typeName
Definition: parsenodes.h:727
char generated
Definition: parsenodes.h:740
Node * raw_default
Definition: parsenodes.h:735
bool is_local
Definition: parsenodes.h:730
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
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:382
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
Definition: tablecmds.c:7406
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:7424
TupleDesc BuildDescForRelation(const List *columns)
Definition: tablecmds.c:1277
static AlterTableCmd * ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5506
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:7353
static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd **cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:6958

References add_column_collation_dependency(), add_column_datatype_dependency(), AddRelationNewConstraints(), Assert, AT_REWRITE_DEFAULT_VAL, ATGetQueueEntry(), ATParseTransformCmd(), ATSimplePermissions(), ATT_FOREIGN_TABLE, ATT_TABLE, RawColumnDefault::attnum, build_column_default(), BuildDescForRelation(), castNode, CatalogTupleUpdate(), check_for_column_name_collision(), check_stack_depth(), CheckAlterTableIsSafe(), CheckAttributeType(), COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, ColumnDef::colname, CommandCounterIncrement(), context, copyObject, AlterTableCmd::def, DomainHasConstraints(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, expression_planner(), find_inheritance_children(), RawColumnDefault::generated, ColumnDef::generated, get_collation_name(), get_typcollation(), getBaseTypeAndTypmod(), GetColumnDefCollation(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, ColumnDef::identity, ColumnDef::identitySequence, ColumnDef::inhcount, InsertPgAttributeTuples(), InvalidObjectAddress, InvokeObjectPostCreateHook, ColumnDef::is_local, ColumnDef::is_not_null, lappend(), lfirst_oid, list_make1, list_make1_oid, makeNode, makeNullConst(), MaxHeapAttributeNumber, RawColumnDefault::missingMode, NameStr, newval, AlteredTableInfo::newvals, NIL, NoLock, NOTICE, ObjectAddressSubSet, ObjectIdGetDatum(), palloc(), palloc0(), RangeVarGetRelid, RawColumnDefault::raw_default, ColumnDef::raw_default, RelationData::rd_att, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, AlteredTableInfo::rewrite, RowExclusiveLock, SearchSysCacheCopy1, SearchSysCacheCopyAttName(), NextValueExpr::seqid, HeapTupleData::t_self, table_close(), table_open(), TupleDescAttr, NextValueExpr::typeId, ColumnDef::typeName, 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 9271 of file tablecmds.c.

9274 {
9276 
9277  Assert(IsA(newConstraint, Constraint));
9278 
9279  /*
9280  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
9281  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
9282  * switch anyway to make it easier to add more code later.
9283  */
9284  switch (newConstraint->contype)
9285  {
9286  case CONSTR_CHECK:
9287  address =
9288  ATAddCheckConstraint(wqueue, tab, rel,
9289  newConstraint, recurse, false, is_readd,
9290  lockmode);
9291  break;
9292 
9293  case CONSTR_FOREIGN:
9294 
9295  /*
9296  * Assign or validate constraint name
9297  */
9298  if (newConstraint->conname)
9299  {
9301  RelationGetRelid(rel),
9302  newConstraint->conname))
9303  ereport(ERROR,
9305  errmsg("constraint \"%s\" for relation \"%s\" already exists",
9306  newConstraint->conname,
9307  RelationGetRelationName(rel))));
9308  }
9309  else
9310  newConstraint->conname =
9313  "fkey",
9314  RelationGetNamespace(rel),
9315  NIL);
9316 
9317  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
9318  newConstraint,
9319  recurse, false,
9320  lockmode);
9321  break;
9322 
9323  default:
9324  elog(ERROR, "unrecognized constraint type: %d",
9325  (int) newConstraint->contype);
9326  }
9327 
9328  return address;
9329 }
@ CONSTR_CHECK
Definition: parsenodes.h:2695
#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:9523

References Assert, ATAddCheckConstraint(), ATAddForeignKeyConstraint(), ChooseConstraintName(), ChooseForeignKeyConstraintNameAddition(), Constraint::conname, CONSTR_CHECK, CONSTR_FOREIGN, 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,
bool  recurse,
bool  recursing 
)
static

Definition at line 7939 of file tablecmds.c.

7941 {
7942  Relation attrelation;
7943  HeapTuple tuple;
7944  Form_pg_attribute attTup;
7946  ObjectAddress address;
7947  ColumnDef *cdef = castNode(ColumnDef, def);
7948  bool ispartitioned;
7949 
7950  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
7951  if (ispartitioned && !recurse)
7952  ereport(ERROR,
7953  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7954  errmsg("cannot add identity to a column of only the partitioned table"),
7955  errhint("Do not specify the ONLY keyword.")));
7956 
7957  if (rel->rd_rel->relispartition && !recursing)
7958  ereport(ERROR,
7959  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7960  errmsg("cannot add identity to a column of a partition"));
7961 
7962  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7963 
7964  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7965  if (!HeapTupleIsValid(tuple))
7966  ereport(ERROR,
7967  (errcode(ERRCODE_UNDEFINED_COLUMN),
7968  errmsg("column \"%s\" of relation \"%s\" does not exist",
7969  colName, RelationGetRelationName(rel))));
7970  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7971  attnum = attTup->attnum;
7972 
7973  /* Can't alter a system attribute */
7974  if (attnum <= 0)
7975  ereport(ERROR,
7976  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7977  errmsg("cannot alter system column \"%s\"",
7978  colName)));
7979 
7980  /*
7981  * Creating a column as identity implies NOT NULL, so adding the identity
7982  * to an existing column that is not NOT NULL would create a state that
7983  * cannot be reproduced without contortions.
7984  */
7985  if (!attTup->attnotnull)
7986  ereport(ERROR,
7987  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7988  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
7989  colName, RelationGetRelationName(rel))));
7990 
7991  if (attTup->attidentity)
7992  ereport(ERROR,
7993  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7994  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
7995  colName, RelationGetRelationName(rel))));
7996 
7997  if (attTup->atthasdef)
7998  ereport(ERROR,
7999  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8000  errmsg("column \"%s\" of relation \"%s\" already has a default value",
8001  colName, RelationGetRelationName(rel))));
8002 
8003  attTup->attidentity = cdef->identity;
8004  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8005 
8006  InvokeObjectPostAlterHook(RelationRelationId,
8007  RelationGetRelid(rel),
8008  attTup->attnum);
8009  ObjectAddressSubSet(address, RelationRelationId,
8010  RelationGetRelid(rel), attnum);
8011  heap_freetuple(tuple);
8012 
8013  table_close(attrelation, RowExclusiveLock);
8014 
8015  /*
8016  * Recurse to propagate the identity column to partitions. Identity is
8017  * not inherited in regular inheritance children.
8018  */
8019  if (recurse && ispartitioned)
8020  {
8021  List *children;
8022  ListCell *lc;
8023 
8024  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8025 
8026  foreach(lc, children)
8027  {
8028  Relation childrel;
8029 
8030  childrel = table_open(lfirst_oid(lc), NoLock);
8031  ATExecAddIdentity(childrel, colName, def, lockmode, recurse, true);
8032  table_close(childrel, NoLock);
8033  }
8034  }
8035 
8036  return address;
8037 }
int errhint(const char *fmt,...)
Definition: elog.c:1317
static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
Definition: tablecmds.c:7939

References attnum, castNode, CatalogTupleUpdate(), ereport, errcode(), errhint(), errmsg(), ERROR, find_inheritance_children(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, ColumnDef::identity, InvokeObjectPostAlterHook, lfirst_oid, NoLock, ObjectAddressSubSet, RelationData::rd_rel, 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 9095 of file tablecmds.c.

9097 {
9098  bool check_rights;
9099  bool skip_build;
9100  bool quiet;
9101  ObjectAddress address;
9102 
9103  Assert(IsA(stmt, IndexStmt));
9104  Assert(!stmt->concurrent);
9105 
9106  /* The IndexStmt has already been through transformIndexStmt */
9107  Assert(stmt->transformed);
9108 
9109  /* suppress schema rights check when rebuilding existing index */
9110  check_rights = !is_rebuild;
9111  /* skip index build if phase 3 will do it or we're reusing an old one */
9112  skip_build = tab->rewrite > 0 || RelFileNumberIsValid(stmt->oldNumber);
9113  /* suppress notices when rebuilding existing index */
9114  quiet = is_rebuild;
9115 
9116  address = DefineIndex(RelationGetRelid(rel),
9117  stmt,
9118  InvalidOid, /* no predefined OID */
9119  InvalidOid, /* no parent index */
9120  InvalidOid, /* no parent constraint */
9121  -1, /* total_parts unknown */
9122  true, /* is_alter_table */
9123  check_rights,
9124  false, /* check_not_in_use - we did it already */
9125  skip_build,
9126  quiet);
9127 
9128  /*
9129  * If TryReuseIndex() stashed a relfilenumber for us, we used it for the
9130  * new index instead of building from scratch. Restore associated fields.
9131  * This may store InvalidSubTransactionId in both fields, in which case
9132  * relcache.c will assume it can rebuild the relcache entry. Hence, do
9133  * this after the CCI that made catalog rows visible to any rebuild. The
9134  * DROP of the old edition of this index will have scheduled the storage
9135  * for deletion at commit, so cancel that pending deletion.
9136  */
9137  if (RelFileNumberIsValid(stmt->oldNumber))
9138  {
9139  Relation irel = index_open(address.objectId, NoLock);
9140 
9141  irel->rd_createSubid = stmt->oldCreateSubid;
9142  irel->rd_firstRelfilelocatorSubid = stmt->oldFirstRelfilelocatorSubid;
9143  RelationPreserveStorage(irel->rd_locator, true);
9144  index_close(irel, NoLock);
9145  }
9146 
9147  return address;
9148 }
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
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:531
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
void RelationPreserveStorage(RelFileLocator rlocator, bool atCommit)
Definition: storage.c:251
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 9179 of file tablecmds.c.

9181 {
9182  Oid index_oid = stmt->indexOid;
9183  Relation indexRel;
9184  char *indexName;
9185  IndexInfo *indexInfo;
9186  char *constraintName;
9187  char constraintType;
9188  ObjectAddress address;
9189  bits16 flags;
9190 
9191  Assert(IsA(stmt, IndexStmt));
9192  Assert(OidIsValid(index_oid));
9193  Assert(stmt->isconstraint);
9194 
9195  /*
9196  * Doing this on partitioned tables is not a simple feature to implement,
9197  * so let's punt for now.
9198  */
9199  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9200  ereport(ERROR,
9201  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9202  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
9203 
9204  indexRel = index_open(index_oid, AccessShareLock);
9205 
9206  indexName = pstrdup(RelationGetRelationName(indexRel));
9207 
9208  indexInfo = BuildIndexInfo(indexRel);
9209 
9210  /* this should have been checked at parse time */
9211  if (!indexInfo->ii_Unique)
9212  elog(ERROR, "index \"%s\" is not unique", indexName);
9213 
9214  /*
9215  * Determine name to assign to constraint. We require a constraint to
9216  * have the same name as the underlying index; therefore, use the index's
9217  * existing name as the default constraint name, and if the user
9218  * explicitly gives some other name for the constraint, rename the index
9219  * to match.
9220  */
9221  constraintName = stmt->idxname;
9222  if (constraintName == NULL)
9223  constraintName = indexName;
9224  else if (strcmp(constraintName, indexName) != 0)
9225  {
9226  ereport(NOTICE,
9227  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
9228  indexName, constraintName)));
9229  RenameRelationInternal(index_oid, constraintName, false, true);
9230  }
9231 
9232  /* Extra checks needed if making primary key */
9233  if (stmt->primary)
9234  index_check_primary_key(rel, indexInfo, true, stmt);
9235 
9236  /* Note we currently don't support EXCLUSION constraints here */
9237  if (stmt->primary)
9238  constraintType = CONSTRAINT_PRIMARY;
9239  else
9240  constraintType = CONSTRAINT_UNIQUE;
9241 
9242  /* Create the catalog entries for the constraint */
9245  (stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
9246  (stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
9247  (stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
9248 
9249  address = index_constraint_create(rel,
9250  index_oid,
9251  InvalidOid,
9252  indexInfo,
9253  constraintName,
9254  constraintType,
9255  flags,
9257  false); /* is_internal */
9258 
9259  index_close(indexRel, NoLock);
9260 
9261  return address;
9262 }
uint16 bits16
Definition: c.h:514
void index_check_primary_key(Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
Definition: index.c:201
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:1881
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2404
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:94
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:95
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:92
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition: index.h:91
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:93
char * pstrdup(const char *in)
Definition: mcxt.c:1696
bool ii_Unique
Definition: execnodes.h:199
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:4097

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

15468 {
15469  Relation parent_rel;
15470  List *children;
15471  ObjectAddress address;
15472  const char *trigger_name;
15473 
15474  /*
15475  * A self-exclusive lock is needed here. See the similar case in
15476  * MergeAttributes() for a full explanation.
15477  */
15478  parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
15479 
15480  /*
15481  * Must be owner of both parent and child -- child was checked by
15482  * ATSimplePermissions call in ATPrepCmd
15483  */
15485 
15486  /* Permanent rels cannot inherit from temporary ones */
15487  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15488  child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
15489  ereport(ERROR,
15490  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15491  errmsg("cannot inherit from temporary relation \"%s\"",
15492  RelationGetRelationName(parent_rel))));
15493 
15494  /* If parent rel is temp, it must belong to this session */
15495  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15496  !parent_rel->rd_islocaltemp)
15497  ereport(ERROR,
15498  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15499  errmsg("cannot inherit from temporary relation of another session")));
15500 
15501  /* Ditto for the child */
15502  if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
15503  !child_rel->rd_islocaltemp)
15504  ereport(ERROR,
15505  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15506  errmsg("cannot inherit to temporary relation of another session")));
15507 
15508  /* Prevent partitioned tables from becoming inheritance parents */
15509  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15510  ereport(ERROR,
15511  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15512  errmsg("cannot inherit from partitioned table \"%s\"",
15513  parent->relname)));
15514 
15515  /* Likewise for partitions */
15516  if (parent_rel->rd_rel->relispartition)
15517  ereport(ERROR,
15518  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15519  errmsg("cannot inherit from a partition")));
15520 
15521  /*
15522  * Prevent circularity by seeing if proposed parent inherits from child.
15523  * (In particular, this disallows making a rel inherit from itself.)
15524  *
15525  * This is not completely bulletproof because of race conditions: in
15526  * multi-level inheritance trees, someone else could concurrently be
15527  * making another inheritance link that closes the loop but does not join
15528  * either of the rels we have locked. Preventing that seems to require
15529  * exclusive locks on the entire inheritance tree, which is a cure worse
15530  * than the disease. find_all_inheritors() will cope with circularity
15531  * anyway, so don't sweat it too much.
15532  *
15533  * We use weakest lock we can on child's children, namely AccessShareLock.
15534  */
15535  children = find_all_inheritors(RelationGetRelid(child_rel),
15536  AccessShareLock, NULL);
15537 
15538  if (list_member_oid(children, RelationGetRelid(parent_rel)))
15539  ereport(ERROR,
15540  (errcode(ERRCODE_DUPLICATE_TABLE),
15541  errmsg("circular inheritance not allowed"),
15542  errdetail("\"%s\" is already a child of \"%s\".",
15543  parent->relname,
15544  RelationGetRelationName(child_rel))));
15545 
15546  /*
15547  * If child_rel has row-level triggers with transition tables, we
15548  * currently don't allow it to become an inheritance child. See also
15549  * prohibitions in ATExecAttachPartition() and CreateTrigger().
15550  */
15551  trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
15552  if (trigger_name != NULL)
15553  ereport(ERROR,
15554  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15555  errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
15556  trigger_name, RelationGetRelationName(child_rel)),
15557  errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
15558 
15559  /* OK to create inheritance */
15560  CreateInheritance(child_rel, parent_rel, false);
15561 
15562  ObjectAddressSet(address, RelationRelationId,
15563  RelationGetRelid(parent_rel));
15564 
15565  /* keep our lock on the parent relation until commit */
15566  table_close(parent_rel, NoLock);
15567 
15568  return address;
15569 }
char * relname
Definition: primnodes.h:82
TriggerDesc * trigdesc
Definition: rel.h:117
static void CreateInheritance(Relation child_rel, Relation parent_rel, bool ispartition)
Definition: tablecmds.c:15579
const char * FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc)
Definition: trigger.c:2272

References AccessShareLock, AT_AddInherit, 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 16292 of file tablecmds.c.

16293 {
16294  Oid relid = RelationGetRelid(rel);
16295  Type typetuple;
16296  Form_pg_type typeform;
16297  Oid typeid;
16298  Relation inheritsRelation,
16299  relationRelation;
16300  SysScanDesc scan;
16301  ScanKeyData key;
16302  AttrNumber table_attno,
16303  type_attno;
16304  TupleDesc typeTupleDesc,
16305  tableTupleDesc;
16306  ObjectAddress tableobj,
16307  typeobj;
16308  HeapTuple classtuple;
16309 
16310  /* Validate the type. */
16311  typetuple = typenameType(NULL, ofTypename, NULL);
16312  check_of_type(typetuple);
16313  typeform = (Form_pg_type) GETSTRUCT(typetuple);
16314  typeid = typeform->oid;
16315 
16316  /* Fail if the table has any inheritance parents. */
16317  inheritsRelation = table_open(InheritsRelationId, AccessShareLock);
16318  ScanKeyInit(&key,
16319  Anum_pg_inherits_inhrelid,
16320  BTEqualStrategyNumber, F_OIDEQ,
16321  ObjectIdGetDatum(relid));
16322  scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
16323  true, NULL, 1, &key);
16325  ereport(ERROR,
16326  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16327  errmsg("typed tables cannot inherit")));
16328  systable_endscan(scan);
16329  table_close(inheritsRelation, AccessShareLock);
16330 
16331  /*
16332  * Check the tuple descriptors for compatibility. Unlike inheritance, we
16333  * require that the order also match. However, attnotnull need not match.
16334  */
16335  typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
16336  tableTupleDesc = RelationGetDescr(rel);
16337  table_attno = 1;
16338  for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
16339  {
16340  Form_pg_attribute type_attr,
16341  table_attr;
16342  const char *type_attname,
16343  *table_attname;
16344 
16345  /* Get the next non-dropped type attribute. */
16346  type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
16347  if (type_attr->attisdropped)
16348  continue;
16349  type_attname = NameStr(type_attr->attname);
16350 
16351  /* Get the next non-dropped table attribute. */
16352  do
16353  {
16354  if (table_attno > tableTupleDesc->natts)
16355  ereport(ERROR,
16356  (errcode(ERRCODE_DATATYPE_MISMATCH),
16357  errmsg("table is missing column \"%s\"",
16358  type_attname)));
16359  table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
16360  table_attno++;
16361  } while (table_attr->attisdropped);
16362  table_attname = NameStr(table_attr->attname);
16363 
16364  /* Compare name. */
16365  if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
16366  ereport(ERROR,
16367  (errcode(ERRCODE_DATATYPE_MISMATCH),
16368  errmsg("table has column \"%s\" where type requires \"%s\"",
16369  table_attname, type_attname)));
16370 
16371  /* Compare type. */
16372  if (table_attr->atttypid != type_attr->atttypid ||
16373  table_attr->atttypmod != type_attr->atttypmod ||
16374  table_attr->attcollation != type_attr->attcollation)
16375  ereport(ERROR,
16376  (errcode(ERRCODE_DATATYPE_MISMATCH),
16377  errmsg("table \"%s\" has different type for column \"%s\"",
16378  RelationGetRelationName(rel), type_attname)));
16379  }
16380  ReleaseTupleDesc(typeTupleDesc);
16381 
16382  /* Any remaining columns at the end of the table had better be dropped. */
16383  for (; table_attno <= tableTupleDesc->natts; table_attno++)
16384  {
16385  Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
16386  table_attno - 1);
16387 
16388  if (!table_attr->attisdropped)
16389  ereport(ERROR,
16390  (errcode(ERRCODE_DATATYPE_MISMATCH),
16391  errmsg("table has extra column \"%s\"",
16392  NameStr(table_attr->attname))));
16393  }
16394 
16395  /* If the table was already typed, drop the existing dependency. */
16396  if (rel->rd_rel->reloftype)
16397  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
16399 
16400  /* Record a dependency on the new type. */
16401  tableobj.classId = RelationRelationId;
16402  tableobj.objectId = relid;
16403  tableobj.objectSubId = 0;
16404  typeobj.classId = TypeRelationId;
16405  typeobj.objectId = typeid;
16406  typeobj.objectSubId = 0;
16407  recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
16408 
16409  /* Update pg_class.reloftype */
16410  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
16411  classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
16412  if (!HeapTupleIsValid(classtuple))
16413  elog(ERROR, "cache lookup failed for relation %u", relid);
16414  ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
16415  CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
16416 
16417  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
16418 
16419  heap_freetuple(classtuple);
16420  table_close(relationRelation, RowExclusiveLock);
16421 
16422  ReleaseSysCache(typetuple);
16423 
16424  return typeobj;
16425 }
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:264
#define NAMEDATALEN
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
Definition: tablecmds.c:16240
void check_of_type(HeapTuple typetuple)
Definition: tablecmds.c:6884
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1850

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

9160 {
9161  ObjectAddress address;
9162 
9164 
9165  /* The CreateStatsStmt has already been through transformStatsStmt */
9166  Assert(stmt->transformed);
9167 
9168  address = CreateStatistics(stmt);
9169 
9170  return address;
9171 }
ObjectAddress CreateStatistics(CreateStatsStmt *stmt)
Definition: statscmds.c:62

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

Referenced by ATExecCmd().

◆ ATExecAlterColumnGenericOptions()

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

Definition at line 14166 of file tablecmds.c.

14170 {
14171  Relation ftrel;
14172  Relation attrel;
14173  ForeignServer *server;
14174  ForeignDataWrapper *fdw;
14175  HeapTuple tuple;
14176  HeapTuple newtuple;
14177  bool isnull;
14178  Datum repl_val[Natts_pg_attribute];
14179  bool repl_null[Natts_pg_attribute];
14180  bool repl_repl[Natts_pg_attribute];
14181  Datum datum;
14182  Form_pg_foreign_table fttableform;
14183  Form_pg_attribute atttableform;
14185  ObjectAddress address;
14186 
14187  if (options == NIL)
14188  return InvalidObjectAddress;
14189 
14190  /* First, determine FDW validator associated to the foreign table. */
14191  ftrel =