PostgreSQL Source Code  git master
tablecmds.c File Reference
#include "postgres.h"
#include "access/attmap.h"
#include "access/genam.h"
#include "access/gist.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 "common/int.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 ATT_PARTITIONED_TABLE   0x0100
 
#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
 
typedef enum addFkConstraintSides addFkConstraintSides
 

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
}
 
enum  addFkConstraintSides { addFkReferencedSide , addFkReferencingSide , addFkBothSides }
 

Functions

static void truncate_check_rel (Oid relid, Form_pg_class reltuple)
 
static void truncate_check_perms (Oid relid, Form_pg_class reltuple)
 
static void truncate_check_activity (Relation rel)
 
static void RangeVarCallbackForTruncate (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
static ListMergeAttributes (List *columns, const List *supers, char relpersistence, bool is_partition, List **supconstr, List **supnotnulls)
 
static ListMergeCheckConstraint (List *constraints, const char *name, Node *expr)
 
static void 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, Oid *attcollids)
 
static int transformFkeyGetPrimaryKey (Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *attcollids, Oid *opclasses, bool *pk_has_without_overlaps)
 
static Oid transformFkeyCheckAttrs (Relation pkrel, int numattrs, int16 *attnums, bool with_period, Oid *opclasses, bool *pk_has_without_overlaps)
 
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, bool hasperiod)
 
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 ObjectAddress ATExecDropNotNull (Relation rel, const char *colName, bool recurse, LOCKMODE lockmode)
 
static void set_attnotnull (List **wqueue, Relation rel, AttrNumber attnum, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetNotNull (List **wqueue, Relation rel, char *constrname, char *colName, bool recurse, bool recursing, 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 void ATPrepAddPrimaryKey (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static ObjectAddress ATExecAddIndex (AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
 
static ObjectAddress ATExecAddStatistics (AlteredTableInfo *tab, Relation rel, CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
 
static ObjectAddress ATExecAddConstraint (List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *newConstraint, bool recurse, bool is_readd, LOCKMODE lockmode)
 
static char * ChooseForeignKeyConstraintNameAddition (List *colnames)
 
static ObjectAddress ATExecAddIndexConstraint (AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, LOCKMODE lockmode)
 
static ObjectAddress ATAddCheckNNConstraint (List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
 
static ObjectAddress ATAddForeignKeyConstraint (List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, bool recurse, bool recursing, LOCKMODE lockmode)
 
static void validateFkOnDeleteSetColumns (int numfks, const int16 *fkattnums, int numfksetcols, const int16 *fksetcolsattnums, List *fksetcols)
 
static ObjectAddress addFkConstraint (addFkConstraintSides fkside, char *constraintname, 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 is_internal, bool with_period)
 
static void addFkRecurseReferenced (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, bool with_period)
 
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, bool with_period)
 
static void CloneForeignKeyConstraints (List **wqueue, Relation parentRel, Relation partitionRel)
 
static void CloneFkReferenced (Relation parentRel, Relation partitionRel)
 
static void CloneFkReferencing (List **wqueue, Relation parentRel, Relation partRel)
 
static void createForeignKeyCheckTriggers (Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
 
static void createForeignKeyActionTriggers (Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
 
static bool tryAttachPartitionForeignKey (ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop, Oid parentInsTrigger, Oid parentUpdTrigger, Relation trigrel)
 
static void GetForeignKeyActionTriggers (Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *deleteTriggerOid, Oid *updateTriggerOid)
 
static void GetForeignKeyCheckTriggers (Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *insertTriggerOid, Oid *updateTriggerOid)
 
static void ATExecDropConstraint (Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool missing_ok, LOCKMODE lockmode)
 
static ObjectAddress dropconstraint_internal (Relation rel, HeapTuple constraintTup, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, 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 void verifyPartitionIndexNotNull (IndexInfo *iinfo, Relation partIdx)
 
static ListGetParentedForeignKeyRefs (Relation partition)
 
static void ATDetachCheckNoForeignKeyRefs (Relation partition)
 
static char GetAttributeCompression (Oid atttypid, const char *compression)
 
static char GetAttributeStorage (Oid atttypid, const char *storagemode)
 
ObjectAddress DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
 
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 166 of file tablecmds.c.

◆ ATT_COMPOSITE_TYPE

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 332 of file tablecmds.c.

◆ ATT_FOREIGN_TABLE

#define ATT_FOREIGN_TABLE   0x0020

Definition at line 333 of file tablecmds.c.

◆ ATT_INDEX

#define ATT_INDEX   0x0008

Definition at line 331 of file tablecmds.c.

◆ ATT_MATVIEW

#define ATT_MATVIEW   0x0004

Definition at line 330 of file tablecmds.c.

◆ ATT_PARTITIONED_INDEX

#define ATT_PARTITIONED_INDEX   0x0040

Definition at line 334 of file tablecmds.c.

◆ ATT_PARTITIONED_TABLE

#define ATT_PARTITIONED_TABLE   0x0100

Definition at line 336 of file tablecmds.c.

◆ ATT_SEQUENCE

#define ATT_SEQUENCE   0x0080

Definition at line 335 of file tablecmds.c.

◆ ATT_TABLE

#define ATT_TABLE   0x0001

Definition at line 328 of file tablecmds.c.

◆ ATT_VIEW

#define ATT_VIEW   0x0002

Definition at line 329 of file tablecmds.c.

◆ child_dependency_type

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

Definition at line 365 of file tablecmds.c.

Typedef Documentation

◆ addFkConstraintSides

◆ AlteredTableInfo

◆ AlterTablePass

◆ ForeignTruncateInfo

◆ NewColumnValue

◆ NewConstraint

typedef struct NewConstraint NewConstraint

◆ OnCommitItem

typedef struct OnCommitItem OnCommitItem

Enumeration Type Documentation

◆ addFkConstraintSides

Enumerator
addFkReferencedSide 
addFkReferencingSide 
addFkBothSides 

Definition at line 353 of file tablecmds.c.

354 {
addFkConstraintSides
Definition: tablecmds.c:354
@ addFkReferencingSide
Definition: tablecmds.c:356
@ addFkBothSides
Definition: tablecmds.c:357
@ addFkReferencedSide
Definition: tablecmds.c:355

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

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

Function Documentation

◆ add_column_collation_dependency()

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

Definition at line 7532 of file tablecmds.c.

7533 {
7534  ObjectAddress myself,
7535  referenced;
7536 
7537  /* We know the default collation is pinned, so don't bother recording it */
7538  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7539  {
7540  myself.classId = RelationRelationId;
7541  myself.objectId = relid;
7542  myself.objectSubId = attnum;
7543  referenced.classId = CollationRelationId;
7544  referenced.objectId = collid;
7545  referenced.objectSubId = 0;
7546  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7547  }
7548 }
#define OidIsValid(objectId)
Definition: c.h:729
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:45

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

7515 {
7516  ObjectAddress myself,
7517  referenced;
7518 
7519  myself.classId = RelationRelationId;
7520  myself.objectId = relid;
7521  myself.objectSubId = attnum;
7522  referenced.classId = TypeRelationId;
7523  referenced.objectId = typid;
7524  referenced.objectSubId = 0;
7525  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7526 }

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

◆ addFkConstraint()

static ObjectAddress addFkConstraint ( addFkConstraintSides  fkside,
char *  constraintname,
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  is_internal,
bool  with_period 
)
static

Definition at line 10353 of file tablecmds.c.

10360 {
10361  ObjectAddress address;
10362  Oid constrOid;
10363  char *conname;
10364  bool conislocal;
10365  int16 coninhcount;
10366  bool connoinherit;
10367 
10368  /*
10369  * Verify relkind for each referenced partition. At the top level, this
10370  * is redundant with a previous check, but we need it when recursing.
10371  */
10372  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
10373  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
10374  ereport(ERROR,
10375  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10376  errmsg("referenced relation \"%s\" is not a table",
10377  RelationGetRelationName(pkrel))));
10378 
10379  /*
10380  * Caller supplies us with a constraint name; however, it may be used in
10381  * this partition, so come up with a different one in that case.
10382  */
10384  RelationGetRelid(rel),
10385  constraintname))
10388  "fkey",
10389  RelationGetNamespace(rel), NIL);
10390  else
10391  conname = constraintname;
10392 
10393  if (fkconstraint->conname == NULL)
10394  fkconstraint->conname = pstrdup(conname);
10395 
10396  if (OidIsValid(parentConstr))
10397  {
10398  conislocal = false;
10399  coninhcount = 1;
10400  connoinherit = false;
10401  }
10402  else
10403  {
10404  conislocal = true;
10405  coninhcount = 0;
10406 
10407  /*
10408  * always inherit for partitioned tables, never for legacy inheritance
10409  */
10410  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
10411  }
10412 
10413  /*
10414  * Record the FK constraint in pg_constraint.
10415  */
10416  constrOid = CreateConstraintEntry(conname,
10417  RelationGetNamespace(rel),
10418  CONSTRAINT_FOREIGN,
10419  fkconstraint->deferrable,
10420  fkconstraint->initdeferred,
10421  fkconstraint->initially_valid,
10422  parentConstr,
10423  RelationGetRelid(rel),
10424  fkattnum,
10425  numfks,
10426  numfks,
10427  InvalidOid, /* not a domain constraint */
10428  indexOid,
10429  RelationGetRelid(pkrel),
10430  pkattnum,
10431  pfeqoperators,
10432  ppeqoperators,
10433  ffeqoperators,
10434  numfks,
10435  fkconstraint->fk_upd_action,
10436  fkconstraint->fk_del_action,
10437  fkdelsetcols,
10438  numfkdelsetcols,
10439  fkconstraint->fk_matchtype,
10440  NULL, /* no exclusion constraint */
10441  NULL, /* no check constraint */
10442  NULL,
10443  conislocal, /* islocal */
10444  coninhcount, /* inhcount */
10445  connoinherit, /* conNoInherit */
10446  with_period, /* conPeriod */
10447  is_internal); /* is_internal */
10448 
10449  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10450 
10451  /*
10452  * In partitioning cases, create the dependency entries for this
10453  * constraint. (For non-partitioned cases, relevant entries were created
10454  * by CreateConstraintEntry.)
10455  *
10456  * On the referenced side, we need the constraint to have an internal
10457  * dependency on its parent constraint; this means that this constraint
10458  * cannot be dropped on its own -- only through the parent constraint. It
10459  * also means the containing partition cannot be dropped on its own, but
10460  * it can be detached, at which point this dependency is removed (after
10461  * verifying that no rows are referenced via this FK.)
10462  *
10463  * When processing the referencing side, we link the constraint via the
10464  * special partitioning dependencies: the parent constraint is the primary
10465  * dependent, and the partition on which the foreign key exists is the
10466  * secondary dependency. That way, this constraint is dropped if either
10467  * of these objects is.
10468  *
10469  * Note that this is only necessary for the subsidiary pg_constraint rows
10470  * in partitions; the topmost row doesn't need any of this.
10471  */
10472  if (OidIsValid(parentConstr))
10473  {
10474  ObjectAddress referenced;
10475 
10476  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
10477 
10478  Assert(fkside != addFkBothSides);
10479  if (fkside == addFkReferencedSide)
10480  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
10481  else
10482  {
10483  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
10484  ObjectAddressSet(referenced, RelationRelationId, RelationGetRelid(rel));
10485  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
10486  }
10487  }
10488 
10489  /* make new constraint visible, in case we add more */
10491 
10492  return address;
10493 }
#define Assert(condition)
Definition: c.h:812
int16_t int16
Definition: c.h:480
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
char * pstrdup(const char *in)
Definition: mcxt.c:1696
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
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, int16 conInhCount, bool conNoInherit, bool conPeriod, bool is_internal)
Definition: pg_constraint.c:51
@ CONSTRAINT_RELATION
#define NIL
Definition: pg_list.h:68
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationGetNamespace(relation)
Definition: rel.h:546
bool initdeferred
Definition: parsenodes.h:2759
char fk_upd_action
Definition: parsenodes.h:2791
char fk_matchtype
Definition: parsenodes.h:2790
bool initially_valid
Definition: parsenodes.h:2761
bool deferrable
Definition: parsenodes.h:2758
char * conname
Definition: parsenodes.h:2757
char fk_del_action
Definition: parsenodes.h:2792
List * fk_attrs
Definition: parsenodes.h:2786
Form_pg_class rd_rel
Definition: rel.h:111
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:9506
void CommandCounterIncrement(void)
Definition: xact.c:1099

References addFkBothSides, addFkReferencedSide, Assert, ChooseConstraintName(), ChooseForeignKeyConstraintNameAddition(), CommandCounterIncrement(), Constraint::conname, CONSTRAINT_RELATION, ConstraintNameIsUsed(), CreateConstraintEntry(), Constraint::deferrable, DEPENDENCY_INTERNAL, DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, ereport, errcode(), errmsg(), ERROR, Constraint::fk_attrs, Constraint::fk_del_action, Constraint::fk_matchtype, Constraint::fk_upd_action, Constraint::initdeferred, Constraint::initially_valid, InvalidOid, NIL, ObjectAddressSet, OidIsValid, pstrdup(), RelationData::rd_rel, recordDependencyOn(), RelationGetNamespace, RelationGetRelationName, and RelationGetRelid.

Referenced by addFkRecurseReferenced(), addFkRecurseReferencing(), ATAddForeignKeyConstraint(), CloneFkReferenced(), and CloneFkReferencing().

◆ addFkRecurseReferenced()

static void addFkRecurseReferenced ( 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,
bool  with_period 
)
static

Definition at line 10528 of file tablecmds.c.

10537 {
10538  Oid deleteTriggerOid,
10539  updateTriggerOid;
10540 
10543 
10544  /*
10545  * Create the action triggers that enforce the constraint.
10546  */
10548  fkconstraint,
10549  parentConstr, indexOid,
10550  parentDelTrigger, parentUpdTrigger,
10551  &deleteTriggerOid, &updateTriggerOid);
10552 
10553  /*
10554  * If the referenced table is partitioned, recurse on ourselves to handle
10555  * each partition. We need one pg_constraint row created for each
10556  * partition in addition to the pg_constraint row for the parent table.
10557  */
10558  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10559  {
10560  PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
10561 
10562  for (int i = 0; i < pd->nparts; i++)
10563  {
10564  Relation partRel;
10565  AttrMap *map;
10566  AttrNumber *mapped_pkattnum;
10567  Oid partIndexId;
10568  ObjectAddress address;
10569 
10570  /* XXX would it be better to acquire these locks beforehand? */
10571  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
10572 
10573  /*
10574  * Map the attribute numbers in the referenced side of the FK
10575  * definition to match the partition's column layout.
10576  */
10578  RelationGetDescr(pkrel),
10579  false);
10580  if (map)
10581  {
10582  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
10583  for (int j = 0; j < numfks; j++)
10584  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
10585  }
10586  else
10587  mapped_pkattnum = pkattnum;
10588 
10589  /* Determine the index to use at this level */
10590  partIndexId = index_get_partition(partRel, indexOid);
10591  if (!OidIsValid(partIndexId))
10592  elog(ERROR, "index for %u not found in partition %s",
10593  indexOid, RelationGetRelationName(partRel));
10594 
10595  /* Create entry at this level ... */
10597  fkconstraint->conname, fkconstraint, rel,
10598  partRel, partIndexId, parentConstr,
10599  numfks, mapped_pkattnum,
10600  fkattnum, pfeqoperators, ppeqoperators,
10601  ffeqoperators, numfkdelsetcols,
10602  fkdelsetcols, true, with_period);
10603  /* ... and recurse to our children */
10604  addFkRecurseReferenced(fkconstraint, rel, partRel,
10605  partIndexId, address.objectId, numfks,
10606  mapped_pkattnum, fkattnum,
10607  pfeqoperators, ppeqoperators, ffeqoperators,
10608  numfkdelsetcols, fkdelsetcols,
10609  old_check_ok,
10610  deleteTriggerOid, updateTriggerOid,
10611  with_period);
10612 
10613  /* Done -- clean up (but keep the lock) */
10614  table_close(partRel, NoLock);
10615  if (map)
10616  {
10617  pfree(mapped_pkattnum);
10618  free_attrmap(map);
10619  }
10620  }
10621  }
10622 }
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
#define elog(elevel,...)
Definition: elog.h:225
int j
Definition: isn.c:73
int i
Definition: isn.c:72
bool CheckRelationLockedByMe(Relation relation, LOCKMODE lockmode, bool orstronger)
Definition: lmgr.c:329
#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
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:71
Oid index_get_partition(Relation partition, Oid indexId)
Definition: partition.c:176
#define RelationGetDescr(relation)
Definition: rel.h:531
Definition: attmap.h:35
AttrNumber * attnums
Definition: attmap.h:36
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12682
static ObjectAddress addFkConstraint(addFkConstraintSides fkside, char *constraintname, 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 is_internal, bool with_period)
Definition: tablecmds.c:10353
static void addFkRecurseReferenced(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, bool with_period)
Definition: tablecmds.c:10528

References addFkConstraint(), addFkReferencedSide, Assert, AttrMap::attnums, build_attrmap_by_name_if_req(), CheckRelationLockedByMe(), Constraint::conname, createForeignKeyActionTriggers(), elog, ERROR, free_attrmap(), i, index_get_partition(), j, NoLock, PartitionDescData::nparts, ObjectAddress::objectId, OidIsValid, PartitionDescData::oids, palloc(), pfree(), RelationData::rd_rel, RelationGetDescr, RelationGetPartitionDesc(), RelationGetRelationName, RelationGetRelid, ShareRowExclusiveLock, table_close(), and table_open().

Referenced by ATAddForeignKeyConstraint(), CloneFkReferenced(), and DetachPartitionFinalize().

◆ 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,
bool  with_period 
)
static

Definition at line 10663 of file tablecmds.c.

10671 {
10672  Oid insertTriggerOid,
10673  updateTriggerOid;
10674 
10675  Assert(OidIsValid(parentConstr));
10678 
10679  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
10680  ereport(ERROR,
10681  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10682  errmsg("foreign key constraints are not supported on foreign tables")));
10683 
10684  /*
10685  * Add the check triggers to it and, if necessary, schedule it to be
10686  * checked in Phase 3.
10687  *
10688  * If the relation is partitioned, drill down to do it to its partitions.
10689  */
10691  RelationGetRelid(pkrel),
10692  fkconstraint,
10693  parentConstr,
10694  indexOid,
10695  parentInsTrigger, parentUpdTrigger,
10696  &insertTriggerOid, &updateTriggerOid);
10697 
10698  if (rel->rd_rel->relkind == RELKIND_RELATION)
10699  {
10700  /*
10701  * Tell Phase 3 to check that the constraint is satisfied by existing
10702  * rows. We can skip this during table creation, when requested
10703  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
10704  * and when we're recreating a constraint following a SET DATA TYPE
10705  * operation that did not impugn its validity.
10706  */
10707  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
10708  {
10709  NewConstraint *newcon;
10710  AlteredTableInfo *tab;
10711 
10712  tab = ATGetQueueEntry(wqueue, rel);
10713 
10714  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
10715  newcon->name = get_constraint_name(parentConstr);
10716  newcon->contype = CONSTR_FOREIGN;
10717  newcon->refrelid = RelationGetRelid(pkrel);
10718  newcon->refindid = indexOid;
10719  newcon->conid = parentConstr;
10720  newcon->conwithperiod = fkconstraint->fk_with_period;
10721  newcon->qual = (Node *) fkconstraint;
10722 
10723  tab->constraints = lappend(tab->constraints, newcon);
10724  }
10725  }
10726  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10727  {
10728  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
10729  Relation trigrel;
10730 
10731  /*
10732  * Triggers of the foreign keys will be manipulated a bunch of times
10733  * in the loop below. To avoid repeatedly opening/closing the trigger
10734  * catalog relation, we open it here and pass it to the subroutines
10735  * called below.
10736  */
10737  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10738 
10739  /*
10740  * Recurse to take appropriate action on each partition; either we
10741  * find an existing constraint to reparent to ours, or we create a new
10742  * one.
10743  */
10744  for (int i = 0; i < pd->nparts; i++)
10745  {
10746  Oid partitionId = pd->oids[i];
10747  Relation partition = table_open(partitionId, lockmode);
10748  List *partFKs;
10749  AttrMap *attmap;
10750  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
10751  bool attached;
10752  ObjectAddress address;
10753  ListCell *cell;
10754 
10755  CheckAlterTableIsSafe(partition);
10756 
10757  attmap = build_attrmap_by_name(RelationGetDescr(partition),
10758  RelationGetDescr(rel),
10759  false);
10760  for (int j = 0; j < numfks; j++)
10761  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
10762 
10763  /* Check whether an existing constraint can be repurposed */
10764  partFKs = copyObject(RelationGetFKeyList(partition));
10765  attached = false;
10766  foreach(cell, partFKs)
10767  {
10768  ForeignKeyCacheInfo *fk;
10769 
10770  fk = lfirst_node(ForeignKeyCacheInfo, cell);
10772  partitionId,
10773  parentConstr,
10774  numfks,
10775  mapped_fkattnum,
10776  pkattnum,
10777  pfeqoperators,
10778  insertTriggerOid,
10779  updateTriggerOid,
10780  trigrel))
10781  {
10782  attached = true;
10783  break;
10784  }
10785  }
10786  if (attached)
10787  {
10788  table_close(partition, NoLock);
10789  continue;
10790  }
10791 
10792  /*
10793  * No luck finding a good constraint to reuse; create our own.
10794  */
10796  fkconstraint->conname, fkconstraint,
10797  partition, pkrel, indexOid, parentConstr,
10798  numfks, pkattnum,
10799  mapped_fkattnum, pfeqoperators,
10800  ppeqoperators, ffeqoperators,
10801  numfkdelsetcols, fkdelsetcols, true,
10802  with_period);
10803 
10804  /* call ourselves to finalize the creation and we're done */
10805  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
10806  indexOid,
10807  address.objectId,
10808  numfks,
10809  pkattnum,
10810  mapped_fkattnum,
10811  pfeqoperators,
10812  ppeqoperators,
10813  ffeqoperators,
10814  numfkdelsetcols,
10815  fkdelsetcols,
10816  old_check_ok,
10817  lockmode,
10818  insertTriggerOid,
10819  updateTriggerOid,
10820  with_period);
10821 
10822  table_close(partition, NoLock);
10823  }
10824 
10825  table_close(trigrel, RowExclusiveLock);
10826  }
10827 }
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:177
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:2734
#define INDEX_MAX_KEYS
#define lfirst_node(type, lc)
Definition: pg_list.h:176
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4657
List * constraints
Definition: tablecmds.c:187
bool fk_with_period
Definition: parsenodes.h:2788
bool skip_validation
Definition: parsenodes.h:2760
Definition: pg_list.h:54
char * name
Definition: tablecmds.c:216
ConstrType contype
Definition: tablecmds.c:217
bool conwithperiod
Definition: tablecmds.c:220
Node * qual
Definition: tablecmds.c:222
Definition: nodes.h:129
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:6410
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, bool with_period)
Definition: tablecmds.c:10663
static void CheckAlterTableIsSafe(Relation rel)
Definition: tablecmds.c:4362
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:11328
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12819

References addFkConstraint(), addFkReferencingSide, Assert, ATGetQueueEntry(), AttrMap::attnums, build_attrmap_by_name(), CheckAlterTableIsSafe(), CheckRelationLockedByMe(), NewConstraint::conid, Constraint::conname, CONSTR_FOREIGN, AlteredTableInfo::constraints, NewConstraint::contype, NewConstraint::conwithperiod, copyObject, createForeignKeyCheckTriggers(), ereport, errcode(), errmsg(), ERROR, Constraint::fk_with_period, get_constraint_name(), i, INDEX_MAX_KEYS, j, lappend(), lfirst_node, NewConstraint::name, NoLock, PartitionDescData::nparts, ObjectAddress::objectId, OidIsValid, PartitionDescData::oids, palloc0(), NewConstraint::qual, RelationData::rd_rel, NewConstraint::refindid, NewConstraint::refrelid, RelationGetDescr, RelationGetFKeyList(), RelationGetPartitionDesc(), RelationGetRelid, RowExclusiveLock, ShareRowExclusiveLock, 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 6444 of file tablecmds.c.

6445 {
6446  switch (cmdtype)
6447  {
6448  case AT_AddColumn:
6449  case AT_AddColumnToView:
6450  return "ADD COLUMN";
6451  case AT_ColumnDefault:
6453  return "ALTER COLUMN ... SET DEFAULT";
6454  case AT_DropNotNull:
6455  return "ALTER COLUMN ... DROP NOT NULL";
6456  case AT_SetNotNull:
6457  return "ALTER COLUMN ... SET NOT NULL";
6458  case AT_SetExpression:
6459  return "ALTER COLUMN ... SET EXPRESSION";
6460  case AT_DropExpression:
6461  return "ALTER COLUMN ... DROP EXPRESSION";
6462  case AT_SetStatistics:
6463  return "ALTER COLUMN ... SET STATISTICS";
6464  case AT_SetOptions:
6465  return "ALTER COLUMN ... SET";
6466  case AT_ResetOptions:
6467  return "ALTER COLUMN ... RESET";
6468  case AT_SetStorage:
6469  return "ALTER COLUMN ... SET STORAGE";
6470  case AT_SetCompression:
6471  return "ALTER COLUMN ... SET COMPRESSION";
6472  case AT_DropColumn:
6473  return "DROP COLUMN";
6474  case AT_AddIndex:
6475  case AT_ReAddIndex:
6476  return NULL; /* not real grammar */
6477  case AT_AddConstraint:
6478  case AT_ReAddConstraint:
6480  case AT_AddIndexConstraint:
6481  return "ADD CONSTRAINT";
6482  case AT_AlterConstraint:
6483  return "ALTER CONSTRAINT";
6484  case AT_ValidateConstraint:
6485  return "VALIDATE CONSTRAINT";
6486  case AT_DropConstraint:
6487  return "DROP CONSTRAINT";
6488  case AT_ReAddComment:
6489  return NULL; /* not real grammar */
6490  case AT_AlterColumnType:
6491  return "ALTER COLUMN ... SET DATA TYPE";
6493  return "ALTER COLUMN ... OPTIONS";
6494  case AT_ChangeOwner:
6495  return "OWNER TO";
6496  case AT_ClusterOn:
6497  return "CLUSTER ON";
6498  case AT_DropCluster:
6499  return "SET WITHOUT CLUSTER";
6500  case AT_SetAccessMethod:
6501  return "SET ACCESS METHOD";
6502  case AT_SetLogged:
6503  return "SET LOGGED";
6504  case AT_SetUnLogged:
6505  return "SET UNLOGGED";
6506  case AT_DropOids:
6507  return "SET WITHOUT OIDS";
6508  case AT_SetTableSpace:
6509  return "SET TABLESPACE";
6510  case AT_SetRelOptions:
6511  return "SET";
6512  case AT_ResetRelOptions:
6513  return "RESET";
6514  case AT_ReplaceRelOptions:
6515  return NULL; /* not real grammar */
6516  case AT_EnableTrig:
6517  return "ENABLE TRIGGER";
6518  case AT_EnableAlwaysTrig:
6519  return "ENABLE ALWAYS TRIGGER";
6520  case AT_EnableReplicaTrig:
6521  return "ENABLE REPLICA TRIGGER";
6522  case AT_DisableTrig:
6523  return "DISABLE TRIGGER";
6524  case AT_EnableTrigAll:
6525  return "ENABLE TRIGGER ALL";
6526  case AT_DisableTrigAll:
6527  return "DISABLE TRIGGER ALL";
6528  case AT_EnableTrigUser:
6529  return "ENABLE TRIGGER USER";
6530  case AT_DisableTrigUser:
6531  return "DISABLE TRIGGER USER";
6532  case AT_EnableRule:
6533  return "ENABLE RULE";
6534  case AT_EnableAlwaysRule:
6535  return "ENABLE ALWAYS RULE";
6536  case AT_EnableReplicaRule:
6537  return "ENABLE REPLICA RULE";
6538  case AT_DisableRule:
6539  return "DISABLE RULE";
6540  case AT_AddInherit:
6541  return "INHERIT";
6542  case AT_DropInherit:
6543  return "NO INHERIT";
6544  case AT_AddOf:
6545  return "OF";
6546  case AT_DropOf:
6547  return "NOT OF";
6548  case AT_ReplicaIdentity:
6549  return "REPLICA IDENTITY";
6550  case AT_EnableRowSecurity:
6551  return "ENABLE ROW SECURITY";
6552  case AT_DisableRowSecurity:
6553  return "DISABLE ROW SECURITY";
6554  case AT_ForceRowSecurity:
6555  return "FORCE ROW SECURITY";
6556  case AT_NoForceRowSecurity:
6557  return "NO FORCE ROW SECURITY";
6558  case AT_GenericOptions:
6559  return "OPTIONS";
6560  case AT_AttachPartition:
6561  return "ATTACH PARTITION";
6562  case AT_DetachPartition:
6563  return "DETACH PARTITION";
6565  return "DETACH PARTITION ... FINALIZE";
6566  case AT_AddIdentity:
6567  return "ALTER COLUMN ... ADD IDENTITY";
6568  case AT_SetIdentity:
6569  return "ALTER COLUMN ... SET";
6570  case AT_DropIdentity:
6571  return "ALTER COLUMN ... DROP IDENTITY";
6572  case AT_ReAddStatistics:
6573  return NULL; /* not real grammar */
6574  }
6575 
6576  return NULL;
6577 }
@ AT_AddIndexConstraint
Definition: parsenodes.h:2381
@ AT_DropOf
Definition: parsenodes.h:2412
@ AT_SetOptions
Definition: parsenodes.h:2369
@ AT_DropIdentity
Definition: parsenodes.h:2424
@ AT_DisableTrigUser
Definition: parsenodes.h:2404
@ AT_DropNotNull
Definition: parsenodes.h:2364
@ AT_AddOf
Definition: parsenodes.h:2411
@ AT_ResetOptions
Definition: parsenodes.h:2370
@ AT_ReplicaIdentity
Definition: parsenodes.h:2413
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2396
@ AT_EnableRowSecurity
Definition: parsenodes.h:2414
@ AT_AddColumnToView
Definition: parsenodes.h:2361
@ AT_ResetRelOptions
Definition: parsenodes.h:2395
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2399
@ AT_DropOids
Definition: parsenodes.h:2391
@ AT_SetIdentity
Definition: parsenodes.h:2423
@ AT_ReAddStatistics
Definition: parsenodes.h:2425
@ AT_SetUnLogged
Definition: parsenodes.h:2390
@ AT_DisableTrig
Definition: parsenodes.h:2400
@ AT_SetCompression
Definition: parsenodes.h:2372
@ AT_DropExpression
Definition: parsenodes.h:2367
@ AT_AddIndex
Definition: parsenodes.h:2374
@ AT_EnableReplicaRule
Definition: parsenodes.h:2407
@ AT_ReAddIndex
Definition: parsenodes.h:2375
@ AT_DropConstraint
Definition: parsenodes.h:2382
@ AT_SetNotNull
Definition: parsenodes.h:2365
@ AT_ClusterOn
Definition: parsenodes.h:2387
@ AT_AddIdentity
Definition: parsenodes.h:2422
@ AT_ForceRowSecurity
Definition: parsenodes.h:2416
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2406
@ AT_SetAccessMethod
Definition: parsenodes.h:2392
@ AT_AlterColumnType
Definition: parsenodes.h:2384
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2421
@ AT_AddInherit
Definition: parsenodes.h:2409
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2378
@ AT_EnableTrig
Definition: parsenodes.h:2397
@ AT_DropColumn
Definition: parsenodes.h:2373
@ AT_ReAddComment
Definition: parsenodes.h:2383
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2385
@ AT_DisableTrigAll
Definition: parsenodes.h:2402
@ AT_EnableRule
Definition: parsenodes.h:2405
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2417
@ AT_DetachPartition
Definition: parsenodes.h:2420
@ AT_SetStatistics
Definition: parsenodes.h:2368
@ AT_AttachPartition
Definition: parsenodes.h:2419
@ AT_AddConstraint
Definition: parsenodes.h:2376
@ AT_DropInherit
Definition: parsenodes.h:2410
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2398
@ AT_SetLogged
Definition: parsenodes.h:2389
@ AT_SetStorage
Definition: parsenodes.h:2371
@ AT_DisableRule
Definition: parsenodes.h:2408
@ AT_DisableRowSecurity
Definition: parsenodes.h:2415
@ AT_SetRelOptions
Definition: parsenodes.h:2394
@ AT_ChangeOwner
Definition: parsenodes.h:2386
@ AT_EnableTrigUser
Definition: parsenodes.h:2403
@ AT_SetExpression
Definition: parsenodes.h:2366
@ AT_ReAddConstraint
Definition: parsenodes.h:2377
@ AT_SetTableSpace
Definition: parsenodes.h:2393
@ AT_GenericOptions
Definition: parsenodes.h:2418
@ AT_ColumnDefault
Definition: parsenodes.h:2362
@ AT_CookedColumnDefault
Definition: parsenodes.h:2363
@ AT_AlterConstraint
Definition: parsenodes.h:2379
@ AT_EnableTrigAll
Definition: parsenodes.h:2401
@ AT_DropCluster
Definition: parsenodes.h:2388
@ AT_ValidateConstraint
Definition: parsenodes.h:2380
@ AT_AddColumn
Definition: parsenodes.h:2360

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

17896 {
17897  List *indexList;
17898  ListCell *l;
17899 
17900  indexList = RelationGetIndexList(rel);
17901 
17902  foreach(l, indexList)
17903  {
17904  Oid indexOid = lfirst_oid(l);
17905  ObjectAddress thisobj;
17906 
17907  thisobj.classId = RelationRelationId;
17908  thisobj.objectId = indexOid;
17909  thisobj.objectSubId = 0;
17910 
17911  /*
17912  * Note: currently, the index will not have its own dependency on the
17913  * namespace, so we don't need to do changeDependencyFor(). There's no
17914  * row type in pg_type, either.
17915  *
17916  * XXX this objsMoved test may be pointless -- surely we have a single
17917  * dependency link from a relation to each index?
17918  */
17919  if (!object_address_present(&thisobj, objsMoved))
17920  {
17921  AlterRelationNamespaceInternal(classRel, indexOid,
17922  oldNspOid, newNspOid,
17923  false, objsMoved);
17924  add_exact_object_address(&thisobj, objsMoved);
17925  }
17926  }
17927 
17928  list_free(indexList);
17929 }
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:4766
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17817

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

17821 {
17822  HeapTuple classTup;
17823  Form_pg_class classForm;
17824  ObjectAddress thisobj;
17825  bool already_done = false;
17826 
17827  /* no rel lock for relkind=c so use LOCKTAG_TUPLE */
17828  classTup = SearchSysCacheLockedCopy1(RELOID, ObjectIdGetDatum(relOid));
17829  if (!HeapTupleIsValid(classTup))
17830  elog(ERROR, "cache lookup failed for relation %u", relOid);
17831  classForm = (Form_pg_class) GETSTRUCT(classTup);
17832 
17833  Assert(classForm->relnamespace == oldNspOid);
17834 
17835  thisobj.classId = RelationRelationId;
17836  thisobj.objectId = relOid;
17837  thisobj.objectSubId = 0;
17838 
17839  /*
17840  * If the object has already been moved, don't move it again. If it's
17841  * already in the right place, don't move it, but still fire the object
17842  * access hook.
17843  */
17844  already_done = object_address_present(&thisobj, objsMoved);
17845  if (!already_done && oldNspOid != newNspOid)
17846  {
17847  ItemPointerData otid = classTup->t_self;
17848 
17849  /* check for duplicate name (more friendly than unique-index failure) */
17850  if (get_relname_relid(NameStr(classForm->relname),
17851  newNspOid) != InvalidOid)
17852  ereport(ERROR,
17853  (errcode(ERRCODE_DUPLICATE_TABLE),
17854  errmsg("relation \"%s\" already exists in schema \"%s\"",
17855  NameStr(classForm->relname),
17856  get_namespace_name(newNspOid))));
17857 
17858  /* classTup is a copy, so OK to scribble on */
17859  classForm->relnamespace = newNspOid;
17860 
17861  CatalogTupleUpdate(classRel, &otid, classTup);
17862  UnlockTuple(classRel, &otid, InplaceUpdateTupleLock);
17863 
17864 
17865  /* Update dependency on schema if caller said so */
17866  if (hasDependEntry &&
17867  changeDependencyFor(RelationRelationId,
17868  relOid,
17869  NamespaceRelationId,
17870  oldNspOid,
17871  newNspOid) != 1)
17872  elog(ERROR, "could not change schema dependency for relation \"%s\"",
17873  NameStr(classForm->relname));
17874  }
17875  else
17876  UnlockTuple(classRel, &classTup->t_self, InplaceUpdateTupleLock);
17877  if (!already_done)
17878  {
17879  add_exact_object_address(&thisobj, objsMoved);
17880 
17881  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
17882  }
17883 
17884  heap_freetuple(classTup);
17885 }
#define NameStr(name)
Definition: c.h:700
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
void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
Definition: lmgr.c:594
#define InplaceUpdateTupleLock
Definition: lockdefs.h:48
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:457
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
ItemPointerData t_self
Definition: htup.h:65
HeapTuple SearchSysCacheLockedCopy1(int cacheId, Datum key1)
Definition: syscache.c:404

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, InplaceUpdateTupleLock, InvalidOid, InvokeObjectPostAlterHook, NameStr, object_address_present(), ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, SearchSysCacheLockedCopy1(), HeapTupleData::t_self, and UnlockTuple().

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

17942 {
17943  Relation depRel;
17944  SysScanDesc scan;
17945  ScanKeyData key[2];
17946  HeapTuple tup;
17947 
17948  /*
17949  * SERIAL sequences are those having an auto dependency on one of the
17950  * table's columns (we don't care *which* column, exactly).
17951  */
17952  depRel = table_open(DependRelationId, AccessShareLock);
17953 
17954  ScanKeyInit(&key[0],
17955  Anum_pg_depend_refclassid,
17956  BTEqualStrategyNumber, F_OIDEQ,
17957  ObjectIdGetDatum(RelationRelationId));
17958  ScanKeyInit(&key[1],
17959  Anum_pg_depend_refobjid,
17960  BTEqualStrategyNumber, F_OIDEQ,
17962  /* we leave refobjsubid unspecified */
17963 
17964  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
17965  NULL, 2, key);
17966 
17967  while (HeapTupleIsValid(tup = systable_getnext(scan)))
17968  {
17969  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
17970  Relation seqRel;
17971 
17972  /* skip dependencies other than auto dependencies on columns */
17973  if (depForm->refobjsubid == 0 ||
17974  depForm->classid != RelationRelationId ||
17975  depForm->objsubid != 0 ||
17976  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
17977  continue;
17978 
17979  /* Use relation_open just in case it's an index */
17980  seqRel = relation_open(depForm->objid, lockmode);
17981 
17982  /* skip non-sequence relations */
17983  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
17984  {
17985  /* No need to keep the lock */
17986  relation_close(seqRel, lockmode);
17987  continue;
17988  }
17989 
17990  /* Fix the pg_class and pg_depend entries */
17991  AlterRelationNamespaceInternal(classRel, depForm->objid,
17992  oldNspOid, newNspOid,
17993  true, objsMoved);
17994 
17995  /*
17996  * Sequences used to have entries in pg_type, but no longer do. If we
17997  * ever re-instate that, we'll need to move the pg_type entry to the
17998  * new namespace, too (using AlterTypeNamespaceInternal).
17999  */
18000  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
18001 
18002  /* Now we can close it. Keep the lock till end of transaction. */
18003  relation_close(seqRel, NoLock);
18004  }
18005 
18006  systable_endscan(scan);
18007 
18009 }
@ DEPENDENCY_AUTO
Definition: dependency.h:34
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:606
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:513
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
#define AccessShareLock
Definition: lockdefs.h:36
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
#define RelationGetForm(relation)
Definition: rel.h: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 4447 of file tablecmds.c.

4449 {
4450  Relation rel;
4451 
4452  /* Caller is required to provide an adequate lock. */
4453  rel = relation_open(context->relid, NoLock);
4454 
4455  CheckAlterTableIsSafe(rel);
4456 
4457  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4458 }
#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:4783

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

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4521 of file tablecmds.c.

4522 {
4523  /*
4524  * This only works if we read catalog tables using MVCC snapshots.
4525  */
4526  ListCell *lcmd;
4528 
4529  foreach(lcmd, cmds)
4530  {
4531  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4532  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4533 
4534  switch (cmd->subtype)
4535  {
4536  /*
4537  * These subcommands rewrite the heap, so require full locks.
4538  */
4539  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4540  * to SELECT */
4541  case AT_SetAccessMethod: /* must rewrite heap */
4542  case AT_SetTableSpace: /* must rewrite heap */
4543  case AT_AlterColumnType: /* must rewrite heap */
4544  cmd_lockmode = AccessExclusiveLock;
4545  break;
4546 
4547  /*
4548  * These subcommands may require addition of toast tables. If
4549  * we add a toast table to a table currently being scanned, we
4550  * might miss data added to the new toast table by concurrent
4551  * insert transactions.
4552  */
4553  case AT_SetStorage: /* may add toast tables, see
4554  * ATRewriteCatalogs() */
4555  cmd_lockmode = AccessExclusiveLock;
4556  break;
4557 
4558  /*
4559  * Removing constraints can affect SELECTs that have been
4560  * optimized assuming the constraint holds true. See also
4561  * CloneFkReferenced.
4562  */
4563  case AT_DropConstraint: /* as DROP INDEX */
4564  case AT_DropNotNull: /* may change some SQL plans */
4565  cmd_lockmode = AccessExclusiveLock;
4566  break;
4567 
4568  /*
4569  * Subcommands that may be visible to concurrent SELECTs
4570  */
4571  case AT_DropColumn: /* change visible to SELECT */
4572  case AT_AddColumnToView: /* CREATE VIEW */
4573  case AT_DropOids: /* used to equiv to DropColumn */
4574  case AT_EnableAlwaysRule: /* may change SELECT rules */
4575  case AT_EnableReplicaRule: /* may change SELECT rules */
4576  case AT_EnableRule: /* may change SELECT rules */
4577  case AT_DisableRule: /* may change SELECT rules */
4578  cmd_lockmode = AccessExclusiveLock;
4579  break;
4580 
4581  /*
4582  * Changing owner may remove implicit SELECT privileges
4583  */
4584  case AT_ChangeOwner: /* change visible to SELECT */
4585  cmd_lockmode = AccessExclusiveLock;
4586  break;
4587 
4588  /*
4589  * Changing foreign table options may affect optimization.
4590  */
4591  case AT_GenericOptions:
4593  cmd_lockmode = AccessExclusiveLock;
4594  break;
4595 
4596  /*
4597  * These subcommands affect write operations only.
4598  */
4599  case AT_EnableTrig:
4600  case AT_EnableAlwaysTrig:
4601  case AT_EnableReplicaTrig:
4602  case AT_EnableTrigAll:
4603  case AT_EnableTrigUser:
4604  case AT_DisableTrig:
4605  case AT_DisableTrigAll:
4606  case AT_DisableTrigUser:
4607  cmd_lockmode = ShareRowExclusiveLock;
4608  break;
4609 
4610  /*
4611  * These subcommands affect write operations only. XXX
4612  * Theoretically, these could be ShareRowExclusiveLock.
4613  */
4614  case AT_ColumnDefault:
4616  case AT_AlterConstraint:
4617  case AT_AddIndex: /* from ADD CONSTRAINT */
4618  case AT_AddIndexConstraint:
4619  case AT_ReplicaIdentity:
4620  case AT_SetNotNull:
4621  case AT_EnableRowSecurity:
4622  case AT_DisableRowSecurity:
4623  case AT_ForceRowSecurity:
4624  case AT_NoForceRowSecurity:
4625  case AT_AddIdentity:
4626  case AT_DropIdentity:
4627  case AT_SetIdentity:
4628  case AT_SetExpression:
4629  case AT_DropExpression:
4630  case AT_SetCompression:
4631  cmd_lockmode = AccessExclusiveLock;
4632  break;
4633 
4634  case AT_AddConstraint:
4635  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4636  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4637  if (IsA(cmd->def, Constraint))
4638  {
4639  Constraint *con = (Constraint *) cmd->def;
4640 
4641  switch (con->contype)
4642  {
4643  case CONSTR_EXCLUSION:
4644  case CONSTR_PRIMARY:
4645  case CONSTR_UNIQUE:
4646 
4647  /*
4648  * Cases essentially the same as CREATE INDEX. We
4649  * could reduce the lock strength to ShareLock if
4650  * we can work out how to allow concurrent catalog
4651  * updates. XXX Might be set down to
4652  * ShareRowExclusiveLock but requires further
4653  * analysis.
4654  */
4655  cmd_lockmode = AccessExclusiveLock;
4656  break;
4657  case CONSTR_FOREIGN:
4658 
4659  /*
4660  * We add triggers to both tables when we add a
4661  * Foreign Key, so the lock level must be at least
4662  * as strong as CREATE TRIGGER.
4663  */
4664  cmd_lockmode = ShareRowExclusiveLock;
4665  break;
4666 
4667  default:
4668  cmd_lockmode = AccessExclusiveLock;
4669  }
4670  }
4671  break;
4672 
4673  /*
4674  * These subcommands affect inheritance behaviour. Queries
4675  * started before us will continue to see the old inheritance
4676  * behaviour, while queries started after we commit will see
4677  * new behaviour. No need to prevent reads or writes to the
4678  * subtable while we hook it up though. Changing the TupDesc
4679  * may be a problem, so keep highest lock.
4680  */
4681  case AT_AddInherit:
4682  case AT_DropInherit:
4683  cmd_lockmode = AccessExclusiveLock;
4684  break;
4685 
4686  /*
4687  * These subcommands affect implicit row type conversion. They
4688  * have affects similar to CREATE/DROP CAST on queries. don't
4689  * provide for invalidating parse trees as a result of such
4690  * changes, so we keep these at AccessExclusiveLock.
4691  */
4692  case AT_AddOf:
4693  case AT_DropOf:
4694  cmd_lockmode = AccessExclusiveLock;
4695  break;
4696 
4697  /*
4698  * Only used by CREATE OR REPLACE VIEW which must conflict
4699  * with an SELECTs currently using the view.
4700  */
4701  case AT_ReplaceRelOptions:
4702  cmd_lockmode = AccessExclusiveLock;
4703  break;
4704 
4705  /*
4706  * These subcommands affect general strategies for performance
4707  * and maintenance, though don't change the semantic results
4708  * from normal data reads and writes. Delaying an ALTER TABLE
4709  * behind currently active writes only delays the point where
4710  * the new strategy begins to take effect, so there is no
4711  * benefit in waiting. In this case the minimum restriction
4712  * applies: we don't currently allow concurrent catalog
4713  * updates.
4714  */
4715  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4716  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4717  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4718  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4719  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4720  cmd_lockmode = ShareUpdateExclusiveLock;
4721  break;
4722 
4723  case AT_SetLogged:
4724  case AT_SetUnLogged:
4725  cmd_lockmode = AccessExclusiveLock;
4726  break;
4727 
4728  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4729  cmd_lockmode = ShareUpdateExclusiveLock;
4730  break;
4731 
4732  /*
4733  * Rel options are more complex than first appears. Options
4734  * are set here for tables, views and indexes; for historical
4735  * reasons these can all be used with ALTER TABLE, so we can't
4736  * decide between them using the basic grammar.
4737  */
4738  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4739  * getTables() */
4740  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4741  * getTables() */
4742  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4743  break;
4744 
4745  case AT_AttachPartition:
4746  cmd_lockmode = ShareUpdateExclusiveLock;
4747  break;
4748 
4749  case AT_DetachPartition:
4750  if (((PartitionCmd *) cmd->def)->concurrent)
4751  cmd_lockmode = ShareUpdateExclusiveLock;
4752  else
4753  cmd_lockmode = AccessExclusiveLock;
4754  break;
4755 
4757  cmd_lockmode = ShareUpdateExclusiveLock;
4758  break;
4759 
4760  default: /* oops */
4761  elog(ERROR, "unrecognized alter table type: %d",
4762  (int) cmd->subtype);
4763  break;
4764  }
4765 
4766  /*
4767  * Take the greatest lockmode from any subcommand
4768  */
4769  if (cmd_lockmode > lockmode)
4770  lockmode = cmd_lockmode;
4771  }
4772 
4773  return lockmode;
4774 }
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:2732
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2733
@ CONSTR_PRIMARY
Definition: parsenodes.h:2731
#define lfirst(lc)
Definition: pg_list.h:172
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2108
AlterTableType subtype
Definition: parsenodes.h:2438
ConstrType contype
Definition: parsenodes.h:2756

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

4477 {
4478  Relation rel;
4479  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4480 
4481  rel = relation_open(relid, lockmode);
4482 
4484 
4485  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4486 }
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4521

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4388 of file tablecmds.c.

4389 {
4390  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4391  stmt->missing_ok ? RVR_MISSING_OK : 0,
4393  stmt);
4394 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:441
@ RVR_MISSING_OK
Definition: namespace.h:72
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:18349

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

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 15771 of file tablecmds.c.

15772 {
15773  List *relations = NIL;
15774  ListCell *l;
15775  ScanKeyData key[1];
15776  Relation rel;
15777  TableScanDesc scan;
15778  HeapTuple tuple;
15779  Oid orig_tablespaceoid;
15780  Oid new_tablespaceoid;
15781  List *role_oids = roleSpecsToIds(stmt->roles);
15782 
15783  /* Ensure we were not asked to move something we can't */
15784  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
15785  stmt->objtype != OBJECT_MATVIEW)
15786  ereport(ERROR,
15787  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15788  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
15789 
15790  /* Get the orig and new tablespace OIDs */
15791  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
15792  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
15793 
15794  /* Can't move shared relations in to or out of pg_global */
15795  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
15796  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
15797  new_tablespaceoid == GLOBALTABLESPACE_OID)
15798  ereport(ERROR,
15799  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
15800  errmsg("cannot move relations in to or out of pg_global tablespace")));
15801 
15802  /*
15803  * Must have CREATE rights on the new tablespace, unless it is the
15804  * database default tablespace (which all users implicitly have CREATE
15805  * rights on).
15806  */
15807  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
15808  {
15809  AclResult aclresult;
15810 
15811  aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
15812  ACL_CREATE);
15813  if (aclresult != ACLCHECK_OK)
15814  aclcheck_error(aclresult, OBJECT_TABLESPACE,
15815  get_tablespace_name(new_tablespaceoid));
15816  }
15817 
15818  /*
15819  * Now that the checks are done, check if we should set either to
15820  * InvalidOid because it is our database's default tablespace.
15821  */
15822  if (orig_tablespaceoid == MyDatabaseTableSpace)
15823  orig_tablespaceoid = InvalidOid;
15824 
15825  if (new_tablespaceoid == MyDatabaseTableSpace)
15826  new_tablespaceoid = InvalidOid;
15827 
15828  /* no-op */
15829  if (orig_tablespaceoid == new_tablespaceoid)
15830  return new_tablespaceoid;
15831 
15832  /*
15833  * Walk the list of objects in the tablespace and move them. This will
15834  * only find objects in our database, of course.
15835  */
15836  ScanKeyInit(&key[0],
15837  Anum_pg_class_reltablespace,
15838  BTEqualStrategyNumber, F_OIDEQ,
15839  ObjectIdGetDatum(orig_tablespaceoid));
15840 
15841  rel = table_open(RelationRelationId, AccessShareLock);
15842  scan = table_beginscan_catalog(rel, 1, key);
15843  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
15844  {
15845  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
15846  Oid relOid = relForm->oid;
15847 
15848  /*
15849  * Do not move objects in pg_catalog as part of this, if an admin
15850  * really wishes to do so, they can issue the individual ALTER
15851  * commands directly.
15852  *
15853  * Also, explicitly avoid any shared tables, temp tables, or TOAST
15854  * (TOAST will be moved with the main table).
15855  */
15856  if (IsCatalogNamespace(relForm->relnamespace) ||
15857  relForm->relisshared ||
15858  isAnyTempNamespace(relForm->relnamespace) ||
15859  IsToastNamespace(relForm->relnamespace))
15860  continue;
15861 
15862  /* Only move the object type requested */
15863  if ((stmt->objtype == OBJECT_TABLE &&
15864  relForm->relkind != RELKIND_RELATION &&
15865  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
15866  (stmt->objtype == OBJECT_INDEX &&
15867  relForm->relkind != RELKIND_INDEX &&
15868  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
15869  (stmt->objtype == OBJECT_MATVIEW &&
15870  relForm->relkind != RELKIND_MATVIEW))
15871  continue;
15872 
15873  /* Check if we are only moving objects owned by certain roles */
15874  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
15875  continue;
15876 
15877  /*
15878  * Handle permissions-checking here since we are locking the tables
15879  * and also to avoid doing a bunch of work only to fail part-way. Note
15880  * that permissions will also be checked by AlterTableInternal().
15881  *
15882  * Caller must be considered an owner on the table to move it.
15883  */
15884  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
15886  NameStr(relForm->relname));
15887 
15888  if (stmt->nowait &&
15890  ereport(ERROR,
15891  (errcode(ERRCODE_OBJECT_IN_USE),
15892  errmsg("aborting because lock on relation \"%s.%s\" is not available",
15893  get_namespace_name(relForm->relnamespace),
15894  NameStr(relForm->relname))));
15895  else
15897 
15898  /* Add to our list of objects to move */
15899  relations = lappend_oid(relations, relOid);
15900  }
15901 
15902  table_endscan(scan);
15904 
15905  if (relations == NIL)
15906  ereport(NOTICE,
15907  (errcode(ERRCODE_NO_DATA_FOUND),
15908  errmsg("no matching relations in tablespace \"%s\" found",
15909  orig_tablespaceoid == InvalidOid ? "(database default)" :
15910  get_tablespace_name(orig_tablespaceoid))));
15911 
15912  /* Everything is locked, loop through and move all of the relations. */
15913  foreach(l, relations)
15914  {
15915  List *cmds = NIL;
15917 
15918  cmd->subtype = AT_SetTableSpace;
15919  cmd->name = stmt->new_tablespacename;
15920 
15921  cmds = lappend(cmds, cmd);
15922 
15924  /* OID is set by AlterTableInternal */
15925  AlterTableInternal(lfirst_oid(l), cmds, false);
15927  }
15928 
15929  return new_tablespaceoid;
15930 }
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:2622
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3810
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4064
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:230
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:212
#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:1243
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:150
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:107
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2003
Oid GetUserId(void)
Definition: miscinit.c:524
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3687
#define makeNode(_type_)
Definition: nodes.h:155
ObjectType get_relkind_objtype(char relkind)
@ OBJECT_MATVIEW
Definition: parsenodes.h:2291
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2310
@ OBJECT_INDEX
Definition: parsenodes.h:2288
@ OBJECT_TABLE
Definition: parsenodes.h:2309
#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:1028
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4476
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 17709 of file tablecmds.c.

17710 {
17711  Relation rel;
17712  Oid relid;
17713  Oid oldNspOid;
17714  Oid nspOid;
17715  RangeVar *newrv;
17716  ObjectAddresses *objsMoved;
17717  ObjectAddress myself;
17718 
17720  stmt->missing_ok ? RVR_MISSING_OK : 0,
17722  stmt);
17723 
17724  if (!OidIsValid(relid))
17725  {
17726  ereport(NOTICE,
17727  (errmsg("relation \"%s\" does not exist, skipping",
17728  stmt->relation->relname)));
17729  return InvalidObjectAddress;
17730  }
17731 
17732  rel = relation_open(relid, NoLock);
17733 
17734  oldNspOid = RelationGetNamespace(rel);
17735 
17736  /* If it's an owned sequence, disallow moving it by itself. */
17737  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
17738  {
17739  Oid tableId;
17740  int32 colId;
17741 
17742  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
17743  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
17744  ereport(ERROR,
17745  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17746  errmsg("cannot move an owned sequence into another schema"),
17747  errdetail("Sequence \"%s\" is linked to table \"%s\".",
17749  get_rel_name(tableId))));
17750  }
17751 
17752  /* Get and lock schema OID and check its permissions. */
17753  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
17754  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
17755 
17756  /* common checks on switching namespaces */
17757  CheckSetNamespace(oldNspOid, nspOid);
17758 
17759  objsMoved = new_object_addresses();
17760  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
17761  free_object_addresses(objsMoved);
17762 
17763  ObjectAddressSet(myself, RelationRelationId, relid);
17764 
17765  if (oldschema)
17766  *oldschema = oldNspOid;
17767 
17768  /* close rel, but keep lock until commit */
17769  relation_close(rel, NoLock);
17770 
17771  return myself;
17772 }
int32_t int32
Definition: c.h:481
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:739
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3459
const ObjectAddress InvalidObjectAddress
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:828
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17780

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

17782 {
17783  Relation classRel;
17784 
17785  Assert(objsMoved != NULL);
17786 
17787  /* OK, modify the pg_class row and pg_depend entry */
17788  classRel = table_open(RelationRelationId, RowExclusiveLock);
17789 
17790  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
17791  nspOid, true, objsMoved);
17792 
17793  /* Fix the table's row type too, if it has one */
17794  if (OidIsValid(rel->rd_rel->reltype))
17795  AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid,
17796  false, /* isImplicitArray */
17797  false, /* ignoreDependent */
17798  false, /* errorOnTableType */
17799  objsMoved);
17800 
17801  /* Fix other dependent stuff */
17802  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
17803  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
17804  objsMoved, AccessExclusiveLock);
17805  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
17806  false, objsMoved);
17807 
17808  table_close(classRel, RowExclusiveLock);
17809 }
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:17939
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17894
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:4166

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

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

◆ ATAddCheckNNConstraint()

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

Definition at line 9548 of file tablecmds.c.

9551 {
9552  List *newcons;
9553  ListCell *lcon;
9554  List *children;
9555  ListCell *child;
9557 
9558  /* Guard against stack overflow due to overly deep inheritance tree. */
9560 
9561  /* At top level, permission check was done in ATPrepCmd, else do it */
9562  if (recursing)
9565 
9566  /*
9567  * Call AddRelationNewConstraints to do the work, making sure it works on
9568  * a copy of the Constraint so transformExpr can't modify the original. It
9569  * returns a list of cooked constraints.
9570  *
9571  * If the constraint ends up getting merged with a pre-existing one, it's
9572  * omitted from the returned list, which is what we want: we do not need
9573  * to do any validation work. That can only happen at child tables,
9574  * though, since we disallow merging at the top level.
9575  */
9576  newcons = AddRelationNewConstraints(rel, NIL,
9577  list_make1(copyObject(constr)),
9578  recursing || is_readd, /* allow_merge */
9579  !recursing, /* is_local */
9580  is_readd, /* is_internal */
9581  NULL); /* queryString not available
9582  * here */
9583 
9584  /* we don't expect more than one constraint here */
9585  Assert(list_length(newcons) <= 1);
9586 
9587  /* Add each to-be-validated constraint to Phase 3's queue */
9588  foreach(lcon, newcons)
9589  {
9590  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
9591 
9592  if (!ccon->skip_validation && ccon->contype != CONSTR_NOTNULL)
9593  {
9594  NewConstraint *newcon;
9595 
9596  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9597  newcon->name = ccon->name;
9598  newcon->contype = ccon->contype;
9599  newcon->qual = ccon->expr;
9600 
9601  tab->constraints = lappend(tab->constraints, newcon);
9602  }
9603 
9604  /* Save the actually assigned name if it was defaulted */
9605  if (constr->conname == NULL)
9606  constr->conname = ccon->name;
9607 
9608  /*
9609  * If adding a not-null constraint, set the pg_attribute flag and tell
9610  * phase 3 to verify existing rows, if needed.
9611  */
9612  if (constr->contype == CONSTR_NOTNULL)
9613  set_attnotnull(wqueue, rel, ccon->attnum, lockmode);
9614 
9615  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
9616  }
9617 
9618  /* At this point we must have a locked-down name to use */
9619  Assert(newcons == NIL || constr->conname != NULL);
9620 
9621  /* Advance command counter in case same table is visited multiple times */
9623 
9624  /*
9625  * If the constraint got merged with an existing constraint, we're done.
9626  * We mustn't recurse to child tables in this case, because they've
9627  * already got the constraint, and visiting them again would lead to an
9628  * incorrect value for coninhcount.
9629  */
9630  if (newcons == NIL)
9631  return address;
9632 
9633  /*
9634  * If adding a NO INHERIT constraint, no need to find our children.
9635  */
9636  if (constr->is_no_inherit)
9637  return address;
9638 
9639  /*
9640  * Propagate to children as appropriate. Unlike most other ALTER
9641  * routines, we have to do this one level of recursion at a time; we can't
9642  * use find_all_inheritors to do it in one pass.
9643  */
9644  children =
9646 
9647  /*
9648  * Check if ONLY was specified with ALTER TABLE. If so, allow the
9649  * constraint creation only if there are no children currently. Error out
9650  * otherwise.
9651  */
9652  if (!recurse && children != NIL)
9653  ereport(ERROR,
9654  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9655  errmsg("constraint must be added to child tables too")));
9656 
9657  /*
9658  * Recurse to create the constraint on each child.
9659  */
9660  foreach(child, children)
9661  {
9662  Oid childrelid = lfirst_oid(child);
9663  Relation childrel;
9664  AlteredTableInfo *childtab;
9665 
9666  /* find_inheritance_children already got lock */
9667  childrel = table_open(childrelid, NoLock);
9668  CheckAlterTableIsSafe(childrel);
9669 
9670  /* Find or create work queue entry for this table */
9671  childtab = ATGetQueueEntry(wqueue, childrel);
9672 
9673  /* Recurse to this child */
9674  ATAddCheckNNConstraint(wqueue, childtab, childrel,
9675  constr, recurse, true, is_readd, lockmode);
9676 
9677  table_close(childrel, NoLock);
9678  }
9679 
9680  return address;
9681 }
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2319
@ CONSTR_NOTNULL
Definition: parsenodes.h:2726
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
void check_stack_depth(void)
Definition: postgres.c:3574
bool is_no_inherit
Definition: parsenodes.h:2762
Oid conoid
Definition: heap.h:39
char * name
Definition: heap.h:40
AttrNumber attnum
Definition: heap.h:41
bool skip_validation
Definition: heap.h:43
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:42
#define ATT_TABLE
Definition: tablecmds.c:328
static void set_attnotnull(List **wqueue, Relation rel, AttrNumber attnum, LOCKMODE lockmode)
Definition: tablecmds.c:7653
static ObjectAddress ATAddCheckNNConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:9548
static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
Definition: tablecmds.c:6587
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:333
#define ATT_PARTITIONED_TABLE
Definition: tablecmds.c:336

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

Referenced by ATExecAddConstraint(), and DetachAddConstraintIfNeeded().

◆ ATAddForeignKeyConstraint()

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

Definition at line 9699 of file tablecmds.c.

9702 {
9703  Relation pkrel;
9704  int16 pkattnum[INDEX_MAX_KEYS] = {0};
9705  int16 fkattnum[INDEX_MAX_KEYS] = {0};
9706  Oid pktypoid[INDEX_MAX_KEYS] = {0};
9707  Oid fktypoid[INDEX_MAX_KEYS] = {0};
9708  Oid pkcolloid[INDEX_MAX_KEYS] = {0};
9709  Oid fkcolloid[INDEX_MAX_KEYS] = {0};
9710  Oid opclasses[INDEX_MAX_KEYS] = {0};
9711  Oid pfeqoperators[INDEX_MAX_KEYS] = {0};
9712  Oid ppeqoperators[INDEX_MAX_KEYS] = {0};
9713  Oid ffeqoperators[INDEX_MAX_KEYS] = {0};
9714  int16 fkdelsetcols[INDEX_MAX_KEYS] = {0};
9715  bool with_period;
9716  bool pk_has_without_overlaps;
9717  int i;
9718  int numfks,
9719  numpks,
9720  numfkdelsetcols;
9721  Oid indexOid;
9722  bool old_check_ok;
9723  ObjectAddress address;
9724  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
9725 
9726  /*
9727  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
9728  * delete rows out from under us.
9729  */
9730  if (OidIsValid(fkconstraint->old_pktable_oid))
9731  pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
9732  else
9733  pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
9734 
9735  /*
9736  * Validity checks (permission checks wait till we have the column
9737  * numbers)
9738  */
9739  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9740  {
9741  if (!recurse)
9742  ereport(ERROR,
9743  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9744  errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9746  RelationGetRelationName(pkrel))));
9747  if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
9748  ereport(ERROR,
9749  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9750  errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9752  RelationGetRelationName(pkrel)),
9753  errdetail("This feature is not yet supported on partitioned tables.")));
9754  }
9755 
9756  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9757  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9758  ereport(ERROR,
9759  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9760  errmsg("referenced relation \"%s\" is not a table",
9761  RelationGetRelationName(pkrel))));
9762 
9763  if (!allowSystemTableMods && IsSystemRelation(pkrel))
9764  ereport(ERROR,
9765  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
9766  errmsg("permission denied: \"%s\" is a system catalog",
9767  RelationGetRelationName(pkrel))));
9768 
9769  /*
9770  * References from permanent or unlogged tables to temp tables, and from
9771  * permanent tables to unlogged tables, are disallowed because the
9772  * referenced data can vanish out from under us. References from temp
9773  * tables to any other table type are also disallowed, because other
9774  * backends might need to run the RI triggers on the perm table, but they
9775  * can't reliably see tuples in the local buffers of other backends.
9776  */
9777  switch (rel->rd_rel->relpersistence)
9778  {
9779  case RELPERSISTENCE_PERMANENT:
9780  if (!RelationIsPermanent(pkrel))
9781  ereport(ERROR,
9782  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9783  errmsg("constraints on permanent tables may reference only permanent tables")));
9784  break;
9785  case RELPERSISTENCE_UNLOGGED:
9786  if (!RelationIsPermanent(pkrel)
9787  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
9788  ereport(ERROR,
9789  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9790  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
9791  break;
9792  case RELPERSISTENCE_TEMP:
9793  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
9794  ereport(ERROR,
9795  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9796  errmsg("constraints on temporary tables may reference only temporary tables")));
9797  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
9798  ereport(ERROR,
9799  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9800  errmsg("constraints on temporary tables must involve temporary tables of this session")));
9801  break;
9802  }
9803 
9804  /*
9805  * Look up the referencing attributes to make sure they exist, and record
9806  * their attnums and type and collation OIDs.
9807  */
9809  fkconstraint->fk_attrs,
9810  fkattnum, fktypoid, fkcolloid);
9811  with_period = fkconstraint->fk_with_period || fkconstraint->pk_with_period;
9812  if (with_period && !fkconstraint->fk_with_period)
9813  ereport(ERROR,
9814  errcode(ERRCODE_INVALID_FOREIGN_KEY),
9815  errmsg("foreign key uses PERIOD on the referenced table but not the referencing table"));
9816 
9817  numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel),
9818  fkconstraint->fk_del_set_cols,
9819  fkdelsetcols, NULL, NULL);
9820  validateFkOnDeleteSetColumns(numfks, fkattnum,
9821  numfkdelsetcols, fkdelsetcols,
9822  fkconstraint->fk_del_set_cols);
9823 
9824  /*
9825  * If the attribute list for the referenced table was omitted, lookup the
9826  * definition of the primary key and use it. Otherwise, validate the
9827  * supplied attribute list. In either case, discover the index OID and
9828  * index opclasses, and the attnums and type and collation OIDs of the
9829  * attributes.
9830  */
9831  if (fkconstraint->pk_attrs == NIL)
9832  {
9833  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
9834  &fkconstraint->pk_attrs,
9835  pkattnum, pktypoid, pkcolloid,
9836  opclasses, &pk_has_without_overlaps);
9837 
9838  /* If the primary key uses WITHOUT OVERLAPS, the fk must use PERIOD */
9839  if (pk_has_without_overlaps && !fkconstraint->fk_with_period)
9840  ereport(ERROR,
9841  errcode(ERRCODE_INVALID_FOREIGN_KEY),
9842  errmsg("foreign key uses PERIOD on the referenced table but not the referencing table"));
9843  }
9844  else
9845  {
9846  numpks = transformColumnNameList(RelationGetRelid(pkrel),
9847  fkconstraint->pk_attrs,
9848  pkattnum, pktypoid, pkcolloid);
9849 
9850  /* Since we got pk_attrs, one should be a period. */
9851  if (with_period && !fkconstraint->pk_with_period)
9852  ereport(ERROR,
9853  errcode(ERRCODE_INVALID_FOREIGN_KEY),
9854  errmsg("foreign key uses PERIOD on the referencing table but not the referenced table"));
9855 
9856  /* Look for an index matching the column list */
9857  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
9858  with_period, opclasses, &pk_has_without_overlaps);
9859  }
9860 
9861  /*
9862  * If the referenced primary key has WITHOUT OVERLAPS, the foreign key
9863  * must use PERIOD.
9864  */
9865  if (pk_has_without_overlaps && !with_period)
9866  ereport(ERROR,
9867  errcode(ERRCODE_INVALID_FOREIGN_KEY),
9868  errmsg("foreign key must use PERIOD when referencing a primary using WITHOUT OVERLAPS"));
9869 
9870  /*
9871  * Now we can check permissions.
9872  */
9873  checkFkeyPermissions(pkrel, pkattnum, numpks);
9874 
9875  /*
9876  * Check some things for generated columns.
9877  */
9878  for (i = 0; i < numfks; i++)
9879  {
9880  char attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
9881 
9882  if (attgenerated)
9883  {
9884  /*
9885  * Check restrictions on UPDATE/DELETE actions, per SQL standard
9886  */
9887  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
9888  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
9889  fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
9890  ereport(ERROR,
9891  (errcode(ERRCODE_SYNTAX_ERROR),
9892  errmsg("invalid %s action for foreign key constraint containing generated column",
9893  "ON UPDATE")));
9894  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
9895  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
9896  ereport(ERROR,
9897  (errcode(ERRCODE_SYNTAX_ERROR),
9898  errmsg("invalid %s action for foreign key constraint containing generated column",
9899  "ON DELETE")));
9900  }
9901  }
9902 
9903  /*
9904  * Some actions are currently unsupported for foreign keys using PERIOD.
9905  */
9906  if (fkconstraint->fk_with_period)
9907  {
9908  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE ||
9909  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
9910  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT)
9911  ereport(ERROR,
9912  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9913  errmsg("unsupported %s action for foreign key constraint using PERIOD",
9914  "ON UPDATE"));
9915 
9916  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_CASCADE ||
9917  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
9918  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
9919  ereport(ERROR,
9920  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9921  errmsg("unsupported %s action for foreign key constraint using PERIOD",
9922  "ON DELETE"));
9923  }
9924 
9925  /*
9926  * Look up the equality operators to use in the constraint.
9927  *
9928  * Note that we have to be careful about the difference between the actual
9929  * PK column type and the opclass' declared input type, which might be
9930  * only binary-compatible with it. The declared opcintype is the right
9931  * thing to probe pg_amop with.
9932  */
9933  if (numfks != numpks)
9934  ereport(ERROR,
9935  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
9936  errmsg("number of referencing and referenced columns for foreign key disagree")));
9937 
9938  /*
9939  * On the strength of a previous constraint, we might avoid scanning
9940  * tables to validate this one. See below.
9941  */
9942  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
9943  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
9944 
9945  for (i = 0; i < numpks; i++)
9946  {
9947  Oid pktype = pktypoid[i];
9948  Oid fktype = fktypoid[i];
9949  Oid fktyped;
9950  Oid pkcoll = pkcolloid[i];
9951  Oid fkcoll = fkcolloid[i];
9952  HeapTuple cla_ht;
9953  Form_pg_opclass cla_tup;
9954  Oid amid;
9955  Oid opfamily;
9956  Oid opcintype;
9957  Oid pfeqop;
9958  Oid ppeqop;
9959  Oid ffeqop;
9960  int16 eqstrategy;
9961  Oid pfeqop_right;
9962 
9963  /* We need several fields out of the pg_opclass entry */
9964  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
9965  if (!HeapTupleIsValid(cla_ht))
9966  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
9967  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
9968  amid = cla_tup->opcmethod;
9969  opfamily = cla_tup->opcfamily;
9970  opcintype = cla_tup->opcintype;
9971  ReleaseSysCache(cla_ht);
9972 
9973  if (with_period)
9974  {
9975  StrategyNumber rtstrategy;
9976  bool for_overlaps = with_period && i == numpks - 1;
9977 
9978  /*
9979  * GiST indexes are required to support temporal foreign keys
9980  * because they combine equals and overlaps.
9981  */
9982  if (amid != GIST_AM_OID)
9983  elog(ERROR, "only GiST indexes are supported for temporal foreign keys");
9984 
9985  rtstrategy = for_overlaps ? RTOverlapStrategyNumber : RTEqualStrategyNumber;
9986 
9987  /*
9988  * An opclass can use whatever strategy numbers it wants, so we
9989  * ask the opclass what number it actually uses instead of our RT*
9990  * constants.
9991  */
9992  eqstrategy = GistTranslateStratnum(opclasses[i], rtstrategy);
9993  if (eqstrategy == InvalidStrategy)
9994  {
9995  HeapTuple tuple;
9996 
9997  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
9998  if (!HeapTupleIsValid(tuple))
9999  elog(ERROR, "cache lookup failed for operator class %u", opclasses[i]);
10000 
10001  ereport(ERROR,
10002  errcode(ERRCODE_UNDEFINED_OBJECT),
10003  for_overlaps
10004  ? errmsg("could not identify an overlaps operator for foreign key")
10005  : errmsg("could not identify an equality operator for foreign key"),
10006  errdetail("Could not translate strategy number %d for operator class \"%s\" for access method \"%s\".",
10007  rtstrategy, NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname), "gist"));
10008  }
10009  }
10010  else
10011  {
10012  /*
10013  * Check it's a btree; currently this can never fail since no
10014  * other index AMs support unique indexes. If we ever did have
10015  * other types of unique indexes, we'd need a way to determine
10016  * which operator strategy number is equality. (We could use
10017  * something like GistTranslateStratnum.)
10018  */
10019  if (amid != BTREE_AM_OID)
10020  elog(ERROR, "only b-tree indexes are supported for foreign keys");
10021  eqstrategy = BTEqualStrategyNumber;
10022  }
10023 
10024  /*
10025  * There had better be a primary equality operator for the index.
10026  * We'll use it for PK = PK comparisons.
10027  */
10028  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
10029  eqstrategy);
10030 
10031  if (!OidIsValid(ppeqop))
10032  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
10033  eqstrategy, opcintype, opcintype, opfamily);
10034 
10035  /*
10036  * Are there equality operators that take exactly the FK type? Assume
10037  * we should look through any domain here.
10038  */
10039  fktyped = getBaseType(fktype);
10040 
10041  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
10042  eqstrategy);
10043  if (OidIsValid(pfeqop))
10044  {
10045  pfeqop_right = fktyped;
10046  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
10047  eqstrategy);
10048  }
10049  else
10050  {
10051  /* keep compiler quiet */
10052  pfeqop_right = InvalidOid;
10053  ffeqop = InvalidOid;
10054  }
10055 
10056  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
10057  {
10058  /*
10059  * Otherwise, look for an implicit cast from the FK type to the
10060  * opcintype, and if found, use the primary equality operator.
10061  * This is a bit tricky because opcintype might be a polymorphic
10062  * type such as ANYARRAY or ANYENUM; so what we have to test is
10063  * whether the two actual column types can be concurrently cast to
10064  * that type. (Otherwise, we'd fail to reject combinations such
10065  * as int[] and point[].)
10066  */
10067  Oid input_typeids[2];
10068  Oid target_typeids[2];
10069 
10070  input_typeids[0] = pktype;
10071  input_typeids[1] = fktype;
10072  target_typeids[0] = opcintype;
10073  target_typeids[1] = opcintype;
10074  if (can_coerce_type(2, input_typeids, target_typeids,
10076  {
10077  pfeqop = ffeqop = ppeqop;
10078  pfeqop_right = opcintype;
10079  }
10080  }
10081 
10082  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
10083  ereport(ERROR,
10084  (errcode(ERRCODE_DATATYPE_MISMATCH),
10085  errmsg("foreign key constraint \"%s\" cannot be implemented",
10086  fkconstraint->conname),
10087  errdetail("Key columns \"%s\" of the referencing table and \"%s\" of the referenced table "
10088  "are of incompatible types: %s and %s.",
10089  strVal(list_nth(fkconstraint->fk_attrs, i)),
10090  strVal(list_nth(fkconstraint->pk_attrs, i)),
10091  format_type_be(fktype),
10092  format_type_be(pktype))));
10093 
10094  /*
10095  * This shouldn't be possible, but better check to make sure we have a
10096  * consistent state for the check below.
10097  */
10098  if ((OidIsValid(pkcoll) && !OidIsValid(fkcoll)) || (!OidIsValid(pkcoll) && OidIsValid(fkcoll)))
10099  elog(ERROR, "key columns are not both collatable");
10100 
10101  if (OidIsValid(pkcoll) && OidIsValid(fkcoll))
10102  {
10103  bool pkcolldet;
10104  bool fkcolldet;
10105 
10106  pkcolldet = get_collation_isdeterministic(pkcoll);
10107  fkcolldet = get_collation_isdeterministic(fkcoll);
10108 
10109  /*
10110  * SQL requires that both collations are the same. This is
10111  * because we need a consistent notion of equality on both
10112  * columns. We relax this by allowing different collations if
10113  * they are both deterministic. (This is also for backward
10114  * compatibility, because PostgreSQL has always allowed this.)
10115  */
10116  if ((!pkcolldet || !fkcolldet) && pkcoll != fkcoll)
10117  ereport(ERROR,
10118  (errcode(ERRCODE_COLLATION_MISMATCH),
10119  errmsg("foreign key constraint \"%s\" cannot be implemented", fkconstraint->conname),
10120  errdetail("Key columns \"%s\" of the referencing table and \"%s\" of the referenced table "
10121  "have incompatible collations: \"%s\" and \"%s\". "
10122  "If either collation is nondeterministic, then both collations have to be the same.",
10123  strVal(list_nth(fkconstraint->fk_attrs, i)),
10124  strVal(list_nth(fkconstraint->pk_attrs, i)),
10125  get_collation_name(fkcoll),
10126  get_collation_name(pkcoll))));
10127  }
10128 
10129  if (old_check_ok)
10130  {
10131  /*
10132  * When a pfeqop changes, revalidate the constraint. We could
10133  * permit intra-opfamily changes, but that adds subtle complexity
10134  * without any concrete benefit for core types. We need not
10135  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
10136  */
10137  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
10138  old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
10139  old_pfeqop_item);
10140  }
10141  if (old_check_ok)
10142  {
10143  Oid old_fktype;
10144  Oid new_fktype;
10145  CoercionPathType old_pathtype;
10146  CoercionPathType new_pathtype;
10147  Oid old_castfunc;
10148  Oid new_castfunc;
10149  Oid old_fkcoll;
10150  Oid new_fkcoll;
10152  fkattnum[i] - 1);
10153 
10154  /*
10155  * Identify coercion pathways from each of the old and new FK-side
10156  * column types to the right (foreign) operand type of the pfeqop.
10157  * We may assume that pg_constraint.conkey is not changing.
10158  */
10159  old_fktype = attr->atttypid;
10160  new_fktype = fktype;
10161  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
10162  &old_castfunc);
10163  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
10164  &new_castfunc);
10165 
10166  old_fkcoll = attr->attcollation;
10167  new_fkcoll = fkcoll;
10168 
10169  /*
10170  * Upon a change to the cast from the FK column to its pfeqop
10171  * operand, revalidate the constraint. For this evaluation, a
10172  * binary coercion cast is equivalent to no cast at all. While
10173  * type implementors should design implicit casts with an eye
10174  * toward consistency of operations like equality, we cannot
10175  * assume here that they have done so.
10176  *
10177  * A function with a polymorphic argument could change behavior
10178  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
10179  * when the cast destination is polymorphic, we only avoid
10180  * revalidation if the input type has not changed at all. Given
10181  * just the core data types and operator classes, this requirement
10182  * prevents no would-be optimizations.
10183  *
10184  * If the cast converts from a base type to a domain thereon, then
10185  * that domain type must be the opcintype of the unique index.
10186  * Necessarily, the primary key column must then be of the domain
10187  * type. Since the constraint was previously valid, all values on
10188  * the foreign side necessarily exist on the primary side and in
10189  * turn conform to the domain. Consequently, we need not treat
10190  * domains specially here.
10191  *
10192  * If the collation changes, revalidation is required, unless both
10193  * collations are deterministic, because those share the same
10194  * notion of equality (because texteq reduces to bitwise
10195  * equality).
10196  *
10197  * We need not directly consider the PK type. It's necessarily
10198  * binary coercible to the opcintype of the unique index column,
10199  * and ri_triggers.c will only deal with PK datums in terms of
10200  * that opcintype. Changing the opcintype also changes pfeqop.
10201  */
10202  old_check_ok = (new_pathtype == old_pathtype &&
10203  new_castfunc == old_castfunc &&
10204  (!IsPolymorphicType(pfeqop_right) ||
10205  new_fktype == old_fktype) &&
10206  (new_fkcoll == old_fkcoll ||
10207  (get_collation_isdeterministic(old_fkcoll) && get_collation_isdeterministic(new_fkcoll))));
10208  }
10209 
10210  pfeqoperators[i] = pfeqop;
10211  ppeqoperators[i] = ppeqop;
10212  ffeqoperators[i] = ffeqop;
10213  }
10214 
10215  /*
10216  * For FKs with PERIOD we need additional operators to check whether the
10217  * referencing row's range is contained by the aggregated ranges of the
10218  * referenced row(s). For rangetypes and multirangetypes this is
10219  * fk.periodatt <@ range_agg(pk.periodatt). Those are the only types we
10220  * support for now. FKs will look these up at "runtime", but we should
10221  * make sure the lookup works here, even if we don't use the values.
10222  */
10223  if (with_period)
10224  {
10225  Oid periodoperoid;
10226  Oid aggedperiodoperoid;
10227 
10228  FindFKPeriodOpers(opclasses[numpks - 1], &periodoperoid, &aggedperiodoperoid);
10229  }
10230 
10231  /* First, create the constraint catalog entry itself. */
10232  address = addFkConstraint(addFkBothSides,
10233  fkconstraint->conname, fkconstraint, rel, pkrel,
10234  indexOid,
10235  InvalidOid, /* no parent constraint */
10236  numfks,
10237  pkattnum,
10238  fkattnum,
10239  pfeqoperators,
10240  ppeqoperators,
10241  ffeqoperators,
10242  numfkdelsetcols,
10243  fkdelsetcols,
10244  false,
10245  with_period);
10246 
10247  /* Next process the action triggers at the referenced side and recurse */
10248  addFkRecurseReferenced(fkconstraint, rel, pkrel,
10249  indexOid,
10250  address.objectId,
10251  numfks,
10252  pkattnum,
10253  fkattnum,
10254  pfeqoperators,
10255  ppeqoperators,
10256  ffeqoperators,
10257  numfkdelsetcols,
10258  fkdelsetcols,
10259  old_check_ok,
10261  with_period);
10262 
10263  /* Lastly create the check triggers at the referencing side and recurse */
10264  addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
10265  indexOid,
10266  address.objectId,
10267  numfks,
10268  pkattnum,
10269  fkattnum,
10270  pfeqoperators,
10271  ppeqoperators,
10272  ffeqoperators,
10273  numfkdelsetcols,
10274  fkdelsetcols,
10275  old_check_ok,
10276  lockmode,
10278  with_period);
10279 
10280  /*
10281  * Done. Close pk table, but keep lock until we've committed.
10282  */
10283  table_close(pkrel, NoLock);
10284 
10285  return address;
10286 }
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
StrategyNumber GistTranslateStratnum(Oid opclass, StrategyNumber strat)
Definition: gistutil.c:1081
bool allowSystemTableMods
Definition: globals.c:129
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:166
char * get_collation_name(Oid colloid)
Definition: lsyscache.c:1035
bool get_collation_isdeterministic(Oid colloid)
Definition: lsyscache.c:1054
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:2746
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2744
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2745
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
void FindFKPeriodOpers(Oid opclass, Oid *containedbyoperoid, Oid *aggedcontainedbyoperoid)
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
uint16 StrategyNumber
Definition: stratnum.h:22
#define RTOverlapStrategyNumber
Definition: stratnum.h:53
#define RTEqualStrategyNumber
Definition: stratnum.h:68
#define InvalidStrategy
Definition: stratnum.h:24
TupleDesc oldDesc
Definition: tablecmds.c:173
List * pk_attrs
Definition: parsenodes.h:2787
List * fk_del_set_cols
Definition: parsenodes.h:2793
Oid old_pktable_oid
Definition: parsenodes.h:2795
List * old_conpfeqop
Definition: parsenodes.h:2794
bool pk_with_period
Definition: parsenodes.h:2789
RangeVar * pktable
Definition: parsenodes.h:2785
bool rd_islocaltemp
Definition: rel.h:61
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:83
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:12461
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, bool with_period, Oid *opclasses, bool *pk_has_without_overlaps)
Definition: tablecmds.c:12310
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:12490
static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, int numfksetcols, const int16 *fksetcolsattnums, List *fksetcols)
Definition: tablecmds.c:10294
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *attcollids, Oid *opclasses, bool *pk_has_without_overlaps)
Definition: tablecmds.c:12207
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids, Oid *attcollids)
Definition: tablecmds.c:12152
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define strVal(v)
Definition: value.h:82

References addFkBothSides, addFkConstraint(), addFkRecurseReferenced(), addFkRecurseReferencing(), allowSystemTableMods, Assert, BTEqualStrategyNumber, can_coerce_type(), checkFkeyPermissions(), COERCION_IMPLICIT, Constraint::conname, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, findFkeyCast(), FindFKPeriodOpers(), Constraint::fk_attrs, Constraint::fk_del_action, Constraint::fk_del_set_cols, Constraint::fk_upd_action, Constraint::fk_with_period, FKCONSTR_ACTION_CASCADE, FKCONSTR_ACTION_SETDEFAULT, FKCONSTR_ACTION_SETNULL, format_type_be(), get_collation_isdeterministic(), get_collation_name(), get_opfamily_member(), getBaseType(), GETSTRUCT, GistTranslateStratnum(), HeapTupleIsValid, i, INDEX_MAX_KEYS, Constraint::initially_valid, InvalidOid, InvalidStrategy, IsSystemRelation(), lfirst_oid, list_head(), list_length(), list_nth(), lnext(), NameStr, NIL, NoLock, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, Constraint::old_conpfeqop, Constraint::old_pktable_oid, AlteredTableInfo::oldDesc, Constraint::pk_attrs, Constraint::pk_with_period, Constraint::pktable, RelationData::rd_islocaltemp, RelationData::rd_rel, RelationGetDescr, RelationGetRelationName, RelationGetRelid, RelationIsPermanent, ReleaseSysCache(), RTEqualStrategyNumber, RTOverlapStrategyNumber, 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 6709 of file tablecmds.c.

6710 {
6711  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6712  {
6713  List *inh;
6714  ListCell *cell;
6715 
6716  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6717  /* first element is the parent rel; must ignore it */
6718  for_each_from(cell, inh, 1)
6719  {
6720  Relation childrel;
6721 
6722  /* find_all_inheritors already got lock */
6723  childrel = table_open(lfirst_oid(cell), NoLock);
6724  CheckAlterTableIsSafe(childrel);
6725  table_close(childrel, NoLock);
6726  }
6727  list_free(inh);
6728  }
6729 }
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 13492 of file tablecmds.c.

13493 {
13494  Assert(expr != NULL);
13495 
13496  for (;;)
13497  {
13498  /* only one varno, so no need to check that */
13499  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
13500  return false;
13501  else if (IsA(expr, RelabelType))
13502  expr = (Node *) ((RelabelType *) expr)->arg;
13503  else if (IsA(expr, CoerceToDomain))
13504  {
13505  CoerceToDomain *d = (CoerceToDomain *) expr;
13506 
13508  return true;
13509  expr = (Node *) d->arg;
13510  }
13511  else if (IsA(expr, FuncExpr))
13512  {
13513  FuncExpr *f = (FuncExpr *) expr;
13514 
13515  switch (f->funcid)
13516  {
13517  case F_TIMESTAMPTZ_TIMESTAMP:
13518  case F_TIMESTAMP_TIMESTAMPTZ:
13520  return true;
13521  else
13522  expr = linitial(f->args);
13523  break;
13524  default:
13525  return true;
13526  }
13527  }
13528  else
13529  return true;
13530  }
13531 }
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:6282
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:1487

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

4786 {
4787  List *wqueue = NIL;
4788  ListCell *lcmd;
4789 
4790  /* Phase 1: preliminary examination of commands, create work queue */
4791  foreach(lcmd, cmds)
4792  {
4793  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4794 
4795  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4796  }
4797 
4798  /* Close the relation, but keep lock until commit */
4799  relation_close(rel, NoLock);
4800 
4801  /* Phase 2: update system catalogs */
4802  ATRewriteCatalogs(&wqueue, lockmode, context);
4803 
4804  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4805  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4806 }
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5213
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4818
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5747

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

20693 {
20694  List *constraints;
20695  ListCell *cell;
20696 
20697  constraints = GetParentedForeignKeyRefs(partition);
20698 
20699  foreach(cell, constraints)
20700  {
20701  Oid constrOid = lfirst_oid(cell);
20702  HeapTuple tuple;
20703  Form_pg_constraint constrForm;
20704  Relation rel;
20705  Trigger trig = {0};
20706 
20707  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
20708  if (!HeapTupleIsValid(tuple))
20709  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
20710  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
20711 
20712  Assert(OidIsValid(constrForm->conparentid));
20713  Assert(constrForm->confrelid == RelationGetRelid(partition));
20714 
20715  /* prevent data changes into the referencing table until commit */
20716  rel = table_open(constrForm->conrelid, ShareLock);
20717 
20718  trig.tgoid = InvalidOid;
20719  trig.tgname = NameStr(constrForm->conname);
20721  trig.tgisinternal = true;
20722  trig.tgconstrrelid = RelationGetRelid(partition);
20723  trig.tgconstrindid = constrForm->conindid;
20724  trig.tgconstraint = constrForm->oid;
20725  trig.tgdeferrable = false;
20726  trig.tginitdeferred = false;
20727  /* we needn't fill in remaining fields */
20728 
20729  RI_PartitionRemove_Check(&trig, rel, partition);
20730 
20731  ReleaseSysCache(tuple);
20732 
20733  table_close(rel, NoLock);
20734  }
20735 }
#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:1723
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:20639
#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 18222 of file tablecmds.c.

18224 {
18225  ListCell *cur_item;
18226 
18227  foreach(cur_item, on_commits)
18228  {
18229  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
18230 
18231  if (!isCommit && oc->creating_subid == mySubid)
18232  {
18233  /* cur_item must be removed */
18235  pfree(oc);
18236  }
18237  else
18238  {
18239  /* cur_item must be preserved */
18240  if (oc->creating_subid == mySubid)
18241  oc->creating_subid = parentSubid;
18242  if (oc->deleting_subid == mySubid)
18243  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
18244  }
18245  }
18246 }
#define InvalidSubTransactionId
Definition: c.h:612
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
SubTransactionId creating_subid
Definition: tablecmds.c:127
SubTransactionId deleting_subid
Definition: tablecmds.c:128
static List * on_commits
Definition: tablecmds.c:131

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

18191 {
18192  ListCell *cur_item;
18193 
18194  foreach(cur_item, on_commits)
18195  {
18196  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
18197 
18198  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
18200  {
18201  /* cur_item must be removed */
18203  pfree(oc);
18204  }
18205  else
18206  {
18207  /* cur_item must be preserved */
18210  }
18211  }
18212 }

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

7069 {
7070  Oid myrelid = RelationGetRelid(rel);
7071  ColumnDef *colDef = castNode(ColumnDef, (*cmd)->def);
7072  bool if_not_exists = (*cmd)->missing_ok;
7073  Relation pgclass,
7074  attrdesc;
7075  HeapTuple reltup;
7076  Form_pg_class relform;
7077  Form_pg_attribute attribute;
7078  int newattnum;
7079  char relkind;
7080  Expr *defval;
7081  List *children;
7082  ListCell *child;
7083  AlterTableCmd *childcmd;
7084  ObjectAddress address;
7085  TupleDesc tupdesc;
7086 
7087  /* since this function recurses, it could be driven to stack overflow */
7089 
7090  /* At top level, permission check was done in ATPrepCmd, else do it */
7091  if (recursing)
7092  ATSimplePermissions((*cmd)->subtype, rel,
7094 
7095  if (rel->rd_rel->relispartition && !recursing)
7096  ereport(ERROR,
7097  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7098  errmsg("cannot add column to a partition")));
7099 
7100  attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
7101 
7102  /*
7103  * Are we adding the column to a recursion child? If so, check whether to
7104  * merge with an existing definition for the column. If we do merge, we
7105  * must not recurse. Children will already have the column, and recursing
7106  * into them would mess up attinhcount.
7107  */
7108  if (colDef->inhcount > 0)
7109  {
7110  HeapTuple tuple;
7111 
7112  /* Does child already have a column by this name? */
7113  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
7114  if (HeapTupleIsValid(tuple))
7115  {
7116  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
7117  Oid ctypeId;
7118  int32 ctypmod;
7119  Oid ccollid;
7120 
7121  /* Child column must match on type, typmod, and collation */
7122  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
7123  if (ctypeId != childatt->atttypid ||
7124  ctypmod != childatt->atttypmod)
7125  ereport(ERROR,
7126  (errcode(ERRCODE_DATATYPE_MISMATCH),
7127  errmsg("child table \"%s\" has different type for column \"%s\"",
7128  RelationGetRelationName(rel), colDef->colname)));
7129  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
7130  if (ccollid != childatt->attcollation)
7131  ereport(ERROR,
7132  (errcode(ERRCODE_COLLATION_MISMATCH),
7133  errmsg("child table \"%s\" has different collation for column \"%s\"",
7134  RelationGetRelationName(rel), colDef->colname),
7135  errdetail("\"%s\" versus \"%s\"",
7136  get_collation_name(ccollid),
7137  get_collation_name(childatt->attcollation))));
7138 
7139  /* Bump the existing child att's inhcount */
7140  if (pg_add_s16_overflow(childatt->attinhcount, 1,
7141  &childatt->attinhcount))
7142  ereport(ERROR,
7143  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
7144  errmsg("too many inheritance parents"));
7145  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
7146 
7147  heap_freetuple(tuple);
7148 
7149  /* Inform the user about the merge */
7150  ereport(NOTICE,
7151  (errmsg("merging definition of column \"%s\" for child \"%s\"",
7152  colDef->colname, RelationGetRelationName(rel))));
7153 
7154  table_close(attrdesc, RowExclusiveLock);
7155 
7156  /* Make the child column change visible */
7158 
7159  return InvalidObjectAddress;
7160  }
7161  }
7162 
7163  /* skip if the name already exists and if_not_exists is true */
7164  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
7165  {
7166  table_close(attrdesc, RowExclusiveLock);
7167  return InvalidObjectAddress;
7168  }
7169 
7170  /*
7171  * Okay, we need to add the column, so go ahead and do parse
7172  * transformation. This can result in queueing up, or even immediately
7173  * executing, subsidiary operations (such as creation of unique indexes);
7174  * so we mustn't do it until we have made the if_not_exists check.
7175  *
7176  * When recursing, the command was already transformed and we needn't do
7177  * so again. Also, if context isn't given we can't transform. (That
7178  * currently happens only for AT_AddColumnToView; we expect that view.c
7179  * passed us a ColumnDef that doesn't need work.)
7180  */
7181  if (context != NULL && !recursing)
7182  {
7183  *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
7184  cur_pass, context);
7185  Assert(*cmd != NULL);
7186  colDef = castNode(ColumnDef, (*cmd)->def);
7187  }
7188 
7189  /*
7190  * Regular inheritance children are independent enough not to inherit the
7191  * identity column from parent hence cannot recursively add identity
7192  * column if the table has inheritance children.
7193  *
7194  * Partitions, on the other hand, are integral part of a partitioned table
7195  * and inherit identity column. Hence propagate identity column down the
7196  * partition hierarchy.
7197  */
7198  if (colDef->identity &&
7199  recurse &&
7200  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE &&
7201  find_inheritance_children(myrelid, NoLock) != NIL)
7202  ereport(ERROR,
7203  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7204  errmsg("cannot recursively add identity column to table that has child tables")));
7205 
7206  pgclass = table_open(RelationRelationId, RowExclusiveLock);
7207 
7208  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
7209  if (!HeapTupleIsValid(reltup))
7210  elog(ERROR, "cache lookup failed for relation %u", myrelid);
7211  relform = (Form_pg_class) GETSTRUCT(reltup);
7212  relkind = relform->relkind;
7213 
7214  /* Determine the new attribute's number */
7215  newattnum = relform->relnatts + 1;
7216  if (newattnum > MaxHeapAttributeNumber)
7217  ereport(ERROR,
7218  (errcode(ERRCODE_TOO_MANY_COLUMNS),
7219  errmsg("tables can have at most %d columns",
7221 
7222  /*
7223  * Construct new attribute's pg_attribute entry.
7224  */
7225  tupdesc = BuildDescForRelation(list_make1(colDef));
7226 
7227  attribute = TupleDescAttr(tupdesc, 0);
7228 
7229  /* Fix up attribute number */
7230  attribute->attnum = newattnum;
7231 
7232  /* make sure datatype is legal for a column */
7233  CheckAttributeType(NameStr(attribute->attname), attribute->atttypid, attribute->attcollation,
7234  list_make1_oid(rel->rd_rel->reltype),
7235  0);
7236 
7237  InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
7238 
7239  table_close(attrdesc, RowExclusiveLock);
7240 
7241  /*
7242  * Update pg_class tuple as appropriate
7243  */
7244  relform->relnatts = newattnum;
7245 
7246  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
7247 
7248  heap_freetuple(reltup);
7249 
7250  /* Post creation hook for new attribute */
7251  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
7252 
7253  table_close(pgclass, RowExclusiveLock);
7254 
7255  /* Make the attribute's catalog entry visible */
7257 
7258  /*
7259  * Store the DEFAULT, if any, in the catalogs
7260  */
7261  if (colDef->raw_default)
7262  {
7263  RawColumnDefault *rawEnt;
7264 
7265  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
7266  rawEnt->attnum = attribute->attnum;
7267  rawEnt->raw_default = copyObject(colDef->raw_default);
7268 
7269  /*
7270  * Attempt to skip a complete table rewrite by storing the specified
7271  * DEFAULT value outside of the heap. This may be disabled inside
7272  * AddRelationNewConstraints if the optimization cannot be applied.
7273  */
7274  rawEnt->missingMode = (!colDef->generated);
7275 
7276  rawEnt->generated = colDef->generated;
7277 
7278  /*
7279  * This function is intended for CREATE TABLE, so it processes a
7280  * _list_ of defaults, but we just do one.
7281  */
7283  false, true, false, NULL);
7284 
7285  /* Make the additional catalog changes visible */
7287 
7288  /*
7289  * Did the request for a missing value work? If not we'll have to do a
7290  * rewrite
7291  */
7292  if (!rawEnt->missingMode)
7294  }
7295 
7296  /*
7297  * Tell Phase 3 to fill in the default expression, if there is one.
7298  *
7299  * If there is no default, Phase 3 doesn't have to do anything, because
7300  * that effectively means that the default is NULL. The heap tuple access
7301  * routines always check for attnum > # of attributes in tuple, and return
7302  * NULL if so, so without any modification of the tuple data we will get
7303  * the effect of NULL values in the new column.
7304  *
7305  * An exception occurs when the new column is of a domain type: the domain
7306  * might have a not-null constraint, or a check constraint that indirectly
7307  * rejects nulls. If there are any domain constraints then we construct
7308  * an explicit NULL default value that will be passed through
7309  * CoerceToDomain processing. (This is a tad inefficient, since it causes
7310  * rewriting the table which we really don't have to do, but the present
7311  * design of domain processing doesn't offer any simple way of checking
7312  * the constraints more directly.)
7313  *
7314  * Note: we use build_column_default, and not just the cooked default
7315  * returned by AddRelationNewConstraints, so that the right thing happens
7316  * when a datatype's default applies.
7317  *
7318  * Note: it might seem that this should happen at the end of Phase 2, so
7319  * that the effects of subsequent subcommands can be taken into account.
7320  * It's intentional that we do it now, though. The new column should be
7321  * filled according to what is said in the ADD COLUMN subcommand, so that
7322  * the effects are the same as if this subcommand had been run by itself
7323  * and the later subcommands had been issued in new ALTER TABLE commands.
7324  *
7325  * We can skip this entirely for relations without storage, since Phase 3
7326  * is certainly not going to touch them. System attributes don't have
7327  * interesting defaults, either.
7328  */
7329  if (RELKIND_HAS_STORAGE(relkind))
7330  {
7331  /*
7332  * For an identity column, we can't use build_column_default(),
7333  * because the sequence ownership isn't set yet. So do it manually.
7334  */
7335  if (colDef->identity)
7336  {
7338 
7339  nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
7340  nve->typeId = attribute->atttypid;
7341 
7342  defval = (Expr *) nve;
7343 
7344  /* must do a rewrite for identity columns */
7346  }
7347  else
7348  defval = (Expr *) build_column_default(rel, attribute->attnum);
7349 
7350  if (!defval && DomainHasConstraints(attribute->atttypid))
7351  {
7352  Oid baseTypeId;
7353  int32 baseTypeMod;
7354  Oid baseTypeColl;
7355 
7356  baseTypeMod = attribute->atttypmod;
7357  baseTypeId = getBaseTypeAndTypmod(attribute->atttypid, &baseTypeMod);
7358  baseTypeColl = get_typcollation(baseTypeId);
7359  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
7360  defval = (Expr *) coerce_to_target_type(NULL,
7361  (Node *) defval,
7362  baseTypeId,
7363  attribute->atttypid,
7364  attribute->atttypmod,
7367  -1);
7368  if (defval == NULL) /* should not happen */
7369  elog(ERROR, "failed to coerce base type to domain");
7370  }
7371 
7372  if (defval)
7373  {
7375 
7377  newval->attnum = attribute->attnum;
7378  newval->expr = expression_planner(defval);
7379  newval->is_generated = (colDef->generated != '\0');
7380 
7381  tab->newvals = lappend(tab->newvals, newval);
7382  }
7383 
7384  if (DomainHasConstraints(attribute->atttypid))
7386 
7387  if (!TupleDescAttr(rel->rd_att, attribute->attnum - 1)->atthasmissing)
7388  {
7389  /*
7390  * If the new column is NOT NULL, and there is no missing value,
7391  * tell Phase 3 it needs to check for NULLs.
7392  */
7393  tab->verify_new_notnull |= colDef->is_not_null;
7394  }
7395  }
7396 
7397  /*
7398  * Add needed dependency entries for the new column.
7399  */
7400  add_column_datatype_dependency(myrelid, newattnum, attribute->atttypid);
7401  add_column_collation_dependency(myrelid, newattnum, attribute->attcollation);
7402 
7403  /*
7404  * Propagate to children as appropriate. Unlike most other ALTER
7405  * routines, we have to do this one level of recursion at a time; we can't
7406  * use find_all_inheritors to do it in one pass.
7407  */
7408  children =
7410 
7411  /*
7412  * If we are told not to recurse, there had better not be any child
7413  * tables; else the addition would put them out of step.
7414  */
7415  if (children && !recurse)
7416  ereport(ERROR,
7417  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7418  errmsg("column must be added to child tables too")));
7419 
7420  /* Children should see column as singly inherited */
7421  if (!recursing)
7422  {
7423  childcmd = copyObject(*cmd);
7424  colDef = castNode(ColumnDef, childcmd->def);
7425  colDef->inhcount = 1;
7426  colDef->is_local = false;
7427  }
7428  else
7429  childcmd = *cmd; /* no need to copy again */
7430 
7431  foreach(child, children)
7432  {
7433  Oid childrelid = lfirst_oid(child);
7434  Relation childrel;
7435  AlteredTableInfo *childtab;
7436 
7437  /* find_inheritance_children already got lock */
7438  childrel = table_open(childrelid, NoLock);
7439  CheckAlterTableIsSafe(childrel);
7440 
7441  /* Find or create work queue entry for this table */
7442  childtab = ATGetQueueEntry(wqueue, childrel);
7443 
7444  /* Recurse to child; return value is ignored */
7445  ATExecAddColumn(wqueue, childtab, childrel,
7446  &childcmd, recurse, true,
7447  lockmode, cur_pass, context);
7448 
7449  table_close(childrel, NoLock);
7450  }
7451 
7452  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
7453  return address;
7454 }
#define AT_REWRITE_DEFAULT_VAL
Definition: event_trigger.h:41
#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
static bool pg_add_s16_overflow(int16 a, int16 b, int16 *result)
Definition: int.h:67
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3056
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:6735
@ 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:190
bool is_not_null
Definition: parsenodes.h:733
char identity
Definition: parsenodes.h:739
RangeVar * identitySequence
Definition: parsenodes.h:740
char * colname
Definition: parsenodes.h:728
TypeName * typeName
Definition: parsenodes.h:729
char generated
Definition: parsenodes.h:742
Node * raw_default
Definition: parsenodes.h:737
bool is_local
Definition: parsenodes.h:732
int16 inhcount
Definition: parsenodes.h:731
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:503
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
Definition: tablecmds.c:7514
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:7532
TupleDesc BuildDescForRelation(const List *columns)
Definition: tablecmds.c:1328
static AlterTableCmd * ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5620
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:7461
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:7065

References add_column_collation_dependency(), add_column_datatype_dependency(), AddRelationNewConstraints(), Assert, AT_REWRITE_DEFAULT_VAL, ATGetQueueEntry(), ATParseTransformCmd(), ATSimplePermissions(), ATT_FOREIGN_TABLE, ATT_PARTITIONED_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(), pg_add_s16_overflow(), 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 9432 of file tablecmds.c.

9435 {
9437 
9438  Assert(IsA(newConstraint, Constraint));
9439 
9440  /*
9441  * Currently, we only expect to see CONSTR_CHECK, CONSTR_NOTNULL and
9442  * CONSTR_FOREIGN nodes arriving here (see the preprocessing done in
9443  * parse_utilcmd.c).
9444  */
9445  switch (newConstraint->contype)
9446  {
9447  case CONSTR_CHECK:
9448  case CONSTR_NOTNULL:
9449  address =
9450  ATAddCheckNNConstraint(wqueue, tab, rel,
9451  newConstraint, recurse, false, is_readd,
9452  lockmode);
9453  break;
9454 
9455  case CONSTR_FOREIGN:
9456 
9457  /*
9458  * Assign or validate constraint name
9459  */
9460  if (newConstraint->conname)
9461  {
9463  RelationGetRelid(rel),
9464  newConstraint->conname))
9465  ereport(ERROR,
9467  errmsg("constraint \"%s\" for relation \"%s\" already exists",
9468  newConstraint->conname,
9469  RelationGetRelationName(rel))));
9470  }
9471  else
9472  newConstraint->conname =
9475  "fkey",
9476  RelationGetNamespace(rel),
9477  NIL);
9478 
9479  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
9480  newConstraint,
9481  recurse, false,
9482  lockmode);
9483  break;
9484 
9485  default:
9486  elog(ERROR, "unrecognized constraint type: %d",
9487  (int) newConstraint->contype);
9488  }
9489 
9490  return address;
9491 }
@ CONSTR_CHECK
Definition: parsenodes.h:2730
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:9699

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

Referenced by ATExecCmd().

◆ ATExecAddIdentity()

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

Definition at line 8034 of file tablecmds.c.

8036 {
8037  Relation attrelation;
8038  HeapTuple tuple;
8039  Form_pg_attribute attTup;
8041  ObjectAddress address;
8042  ColumnDef *cdef = castNode(ColumnDef, def);
8043  bool ispartitioned;
8044 
8045  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8046  if (ispartitioned && !recurse)
8047  ereport(ERROR,
8048  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8049  errmsg("cannot add identity to a column of only the partitioned table"),
8050  errhint("Do not specify the ONLY keyword.")));
8051 
8052  if (rel->rd_rel->relispartition && !recursing)
8053  ereport(ERROR,
8054  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8055  errmsg("cannot add identity to a column of a partition"));
8056 
8057  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8058 
8059  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8060  if (!HeapTupleIsValid(tuple))
8061  ereport(ERROR,
8062  (errcode(ERRCODE_UNDEFINED_COLUMN),
8063  errmsg("column \"%s\" of relation \"%s\" does not exist",
8064  colName, RelationGetRelationName(rel))));
8065  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8066  attnum = attTup->attnum;
8067 
8068  /* Can't alter a system attribute */
8069  if (attnum <= 0)
8070  ereport(ERROR,
8071  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8072  errmsg("cannot alter system column \"%s\"",
8073  colName)));
8074 
8075  /*
8076  * Creating a column as identity implies NOT NULL, so adding the identity
8077  * to an existing column that is not NOT NULL would create a state that
8078  * cannot be reproduced without contortions.
8079  */
8080  if (!attTup->attnotnull)
8081  ereport(ERROR,
8082  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8083  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
8084  colName, RelationGetRelationName(rel))));
8085 
8086  if (attTup->attidentity)
8087  ereport(ERROR,
8088  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8089  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
8090  colName, RelationGetRelationName(rel))));
8091 
8092  if (attTup->atthasdef)
8093  ereport(ERROR,
8094  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8095  errmsg("column \"%s\" of relation \"%s\" already has a default value",
8096  colName, RelationGetRelationName(rel))));
8097 
8098  attTup->attidentity = cdef->identity;
8099  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8100 
8101  InvokeObjectPostAlterHook(RelationRelationId,
8102  RelationGetRelid(rel),
8103  attTup->attnum);
8104  ObjectAddressSubSet(address, RelationRelationId,
8105  RelationGetRelid(rel), attnum);
8106  heap_freetuple(tuple);
8107 
8108  table_close(attrelation, RowExclusiveLock);
8109 
8110  /*
8111  * Recurse to propagate the identity column to partitions. Identity is
8112  * not inherited in regular inheritance children.
8113  */
8114  if (recurse && ispartitioned)
8115  {
8116  List *children;
8117  ListCell *lc;
8118 
8119  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8120 
8121  foreach(lc, children)
8122  {
8123  Relation childrel;
8124 
8125  childrel = table_open(lfirst_oid(lc), NoLock);
8126  ATExecAddIdentity(childrel, colName, def, lockmode, recurse, true);
8127  table_close(childrel, NoLock);
8128  }
8129  }
8130 
8131  return address;
8132 }
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:8034

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

9258 {
9259  bool check_rights;
9260  bool skip_build;
9261  bool quiet;
9262  ObjectAddress address;
9263 
9264  Assert(IsA(stmt, IndexStmt));
9265  Assert(!stmt->concurrent);
9266 
9267  /* The IndexStmt has already been through transformIndexStmt */
9268  Assert(stmt->transformed);
9269 
9270  /* suppress schema rights check when rebuilding existing index */
9271  check_rights = !is_rebuild;
9272  /* skip index build if phase 3 will do it or we're reusing an old one */
9273  skip_build = tab->rewrite > 0 || RelFileNumberIsValid(stmt->oldNumber);
9274  /* suppress notices when rebuilding existing index */
9275  quiet = is_rebuild;
9276 
9277  address = DefineIndex(RelationGetRelid(rel),
9278  stmt,
9279  InvalidOid, /* no predefined OID */
9280  InvalidOid, /* no parent index */
9281  InvalidOid, /* no parent constraint */
9282  -1, /* total_parts unknown */
9283  true, /* is_alter_table */
9284  check_rights,
9285  false, /* check_not_in_use - we did it already */
9286  skip_build,
9287  quiet);
9288 
9289  /*
9290  * If TryReuseIndex() stashed a relfilenumber for us, we used it for the
9291  * new index instead of building from scratch. Restore associated fields.
9292  * This may store InvalidSubTransactionId in both fields, in which case
9293  * relcache.c will assume it can rebuild the relcache entry. Hence, do
9294  * this after the CCI that made catalog rows visible to any rebuild. The
9295  * DROP of the old edition of this index will have scheduled the storage
9296  * for deletion at commit, so cancel that pending deletion.
9297  */
9298  if (RelFileNumberIsValid(stmt->oldNumber))
9299  {
9300  Relation irel = index_open(address.objectId, NoLock);
9301 
9302  irel->rd_createSubid = stmt->oldCreateSubid;
9303  irel->rd_firstRelfilelocatorSubid = stmt->oldFirstRelfilelocatorSubid;
9304  RelationPreserveStorage(irel->rd_locator, true);
9305  index_close(irel, NoLock);
9306  }
9307 
9308  return address;
9309 }
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:543
#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 9340 of file tablecmds.c.

9342 {
9343  Oid index_oid = stmt->indexOid;
9344  Relation indexRel;
9345  char *indexName;
9346  IndexInfo *indexInfo;
9347  char *constraintName;
9348  char constraintType;
9349  ObjectAddress address;
9350  bits16 flags;
9351 
9352  Assert(IsA(stmt, IndexStmt));
9353  Assert(OidIsValid(index_oid));
9354  Assert(stmt->isconstraint);
9355 
9356  /*
9357  * Doing this on partitioned tables is not a simple feature to implement,
9358  * so let's punt for now.
9359  */
9360  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9361  ereport(ERROR,
9362  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9363  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
9364 
9365  indexRel = index_open(index_oid, AccessShareLock);
9366 
9367  indexName = pstrdup(RelationGetRelationName(indexRel));
9368 
9369  indexInfo = BuildIndexInfo(indexRel);
9370 
9371  /* this should have been checked at parse time */
9372  if (!indexInfo->ii_Unique)
9373  elog(ERROR, "index \"%s\" is not unique", indexName);
9374 
9375  /*
9376  * Determine name to assign to constraint. We require a constraint to
9377  * have the same name as the underlying index; therefore, use the index's
9378  * existing name as the default constraint name, and if the user
9379  * explicitly gives some other name for the constraint, rename the index
9380  * to match.
9381  */
9382  constraintName = stmt->idxname;
9383  if (constraintName == NULL)
9384  constraintName = indexName;
9385  else if (strcmp(constraintName, indexName) != 0)
9386  {
9387  ereport(NOTICE,
9388  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
9389  indexName, constraintName)));
9390  RenameRelationInternal(index_oid, constraintName, false, true);
9391  }
9392 
9393  /* Extra checks needed if making primary key */
9394  if (stmt->primary)
9395  index_check_primary_key(rel, indexInfo, true, stmt);
9396 
9397  /* Note we currently don't support EXCLUSION constraints here */
9398  if (stmt->primary)
9399  constraintType = CONSTRAINT_PRIMARY;
9400  else
9401  constraintType = CONSTRAINT_UNIQUE;
9402 
9403  /* Create the catalog entries for the constraint */
9406  (stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
9407  (stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
9408  (stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
9409 
9410  address = index_constraint_create(rel,
9411  index_oid,
9412  InvalidOid,
9413  indexInfo,
9414  constraintName,
9415  constraintType,
9416  flags,
9418  false); /* is_internal */
9419 
9420  index_close(indexRel, NoLock);
9421 
9422  return address;
9423 }
uint16 bits16
Definition: c.h:493
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:1883
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2425
#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
bool ii_Unique
Definition: execnodes.h:199
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:4183

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

16048 {
16049  Relation parent_rel;
16050  List *children;
16051  ObjectAddress address;
16052  const char *trigger_name;
16053 
16054  /*
16055  * A self-exclusive lock is needed here. See the similar case in
16056  * MergeAttributes() for a full explanation.
16057  */
16058  parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
16059 
16060  /*
16061  * Must be owner of both parent and child -- child was checked by
16062  * ATSimplePermissions call in ATPrepCmd
16063  */
16064  ATSimplePermissions(AT_AddInherit, parent_rel,
16066 
16067  /* Permanent rels cannot inherit from temporary ones */
16068  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
16069  child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
16070  ereport(ERROR,
16071  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16072  errmsg("cannot inherit from temporary relation \"%s\"",
16073  RelationGetRelationName(parent_rel))));
16074 
16075  /* If parent rel is temp, it must belong to this session */
16076  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
16077  !parent_rel->rd_islocaltemp)
16078  ereport(ERROR,
16079  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16080  errmsg("cannot inherit from temporary relation of another session")));
16081 
16082  /* Ditto for the child */
16083  if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
16084  !child_rel->rd_islocaltemp)
16085  ereport(ERROR,
16086  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16087  errmsg("cannot inherit to temporary relation of another session")));
16088 
16089  /* Prevent partitioned tables from becoming inheritance parents */
16090  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16091  ereport(ERROR,
16092  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16093  errmsg("cannot inherit from partitioned table \"%s\"",
16094  parent->relname)));
16095 
16096  /* Likewise for partitions */
16097  if (parent_rel->rd_rel->relispartition)
16098  ereport(ERROR,
16099  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
16100  errmsg("cannot inherit from a partition")));
16101 
16102  /*
16103  * Prevent circularity by seeing if proposed parent inherits from child.
16104  * (In particular, this disallows making a rel inherit from itself.)
16105  *
16106  * This is not completely bulletproof because of race conditions: in
16107  * multi-level inheritance trees, someone else could concurrently be
16