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

Go to the source code of this file.

Data Structures

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

Macros

#define AT_NUM_PASSES   (AT_PASS_MISC + 1)
 
#define ATT_TABLE   0x0001
 
#define ATT_VIEW   0x0002
 
#define ATT_MATVIEW   0x0004
 
#define ATT_INDEX   0x0008
 
#define ATT_COMPOSITE_TYPE   0x0010
 
#define ATT_FOREIGN_TABLE   0x0020
 
#define ATT_PARTITIONED_INDEX   0x0040
 
#define ATT_SEQUENCE   0x0080
 
#define child_dependency_type(child_is_partition)    ((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
 

Typedefs

typedef struct OnCommitItem OnCommitItem
 
typedef enum AlterTablePass AlterTablePass
 
typedef struct AlteredTableInfo AlteredTableInfo
 
typedef struct NewConstraint NewConstraint
 
typedef struct NewColumnValue NewColumnValue
 
typedef struct ForeignTruncateInfo ForeignTruncateInfo
 
typedef struct SplitPartitionContext SplitPartitionContext
 

Enumerations

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

Functions

static void truncate_check_rel (Oid relid, Form_pg_class reltuple)
 
static void truncate_check_perms (Oid relid, Form_pg_class reltuple)
 
static void truncate_check_activity (Relation rel)
 
static void RangeVarCallbackForTruncate (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
static ListMergeAttributes (List *columns, const List *supers, char relpersistence, bool is_partition, List **supconstr)
 
static ListMergeCheckConstraint (List *constraints, const char *name, Node *expr)
 
static void MergeChildAttribute (List *inh_columns, int exist_attno, int newcol_attno, const ColumnDef *newdef)
 
static ColumnDefMergeInheritedAttribute (List *inh_columns, int exist_attno, const ColumnDef *newdef)
 
static void MergeAttributesIntoExisting (Relation child_rel, Relation parent_rel, bool ispartition)
 
static void MergeConstraintsIntoExisting (Relation child_rel, Relation parent_rel)
 
static void StoreCatalogInheritance (Oid relationId, List *supers, bool child_is_partition)
 
static void StoreCatalogInheritance1 (Oid relationId, Oid parentOid, int32 seqNumber, Relation inhRelation, bool child_is_partition)
 
static int findAttrByName (const char *attributeName, const List *columns)
 
static void AlterIndexNamespaces (Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
 
static void AlterSeqNamespaces (Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
 
static ObjectAddress ATExecAlterConstraint (Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
 
static bool ATExecAlterConstrRecurse (Constraint *cmdcon, Relation conrel, Relation tgrel, Relation rel, HeapTuple contuple, List **otherrelids, LOCKMODE lockmode)
 
static ObjectAddress ATExecValidateConstraint (List **wqueue, Relation rel, char *constrName, bool recurse, bool recursing, LOCKMODE lockmode)
 
static int transformColumnNameList (Oid relId, List *colList, int16 *attnums, Oid *atttypids)
 
static int transformFkeyGetPrimaryKey (Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
 
static Oid transformFkeyCheckAttrs (Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
 
static void checkFkeyPermissions (Relation rel, int16 *attnums, int natts)
 
static CoercionPathType findFkeyCast (Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
 
static void validateForeignKeyConstraint (char *conname, Relation rel, Relation pkrel, Oid pkindOid, Oid constraintOid)
 
static void CheckAlterTableIsSafe (Relation rel)
 
static void ATController (AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATPrepCmd (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATRewriteCatalogs (List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATExecCmd (List **wqueue, AlteredTableInfo *tab, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
 
static AlterTableCmdATParseTransformCmd (List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
 
static void ATRewriteTables (AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATRewriteTable (AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 
static AlteredTableInfoATGetQueueEntry (List **wqueue, Relation rel)
 
static void ATSimplePermissions (AlterTableType cmdtype, Relation rel, int allowed_targets)
 
static void ATSimpleRecursion (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATCheckPartitionsNotInUse (Relation rel, LOCKMODE lockmode)
 
static void ATTypedTableRecursion (List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static Listfind_typed_table_dependencies (Oid typeOid, const char *typeName, DropBehavior behavior)
 
static void ATPrepAddColumn (List **wqueue, Relation rel, bool recurse, bool recursing, bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static ObjectAddress ATExecAddColumn (List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd **cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTablePass cur_pass, AlterTableUtilityContext *context)
 
static bool check_for_column_name_collision (Relation rel, const char *colname, bool if_not_exists)
 
static void add_column_datatype_dependency (Oid relid, int32 attnum, Oid typid)
 
static void add_column_collation_dependency (Oid relid, int32 attnum, Oid collid)
 
static void ATPrepDropNotNull (Relation rel, bool recurse, bool recursing)
 
static ObjectAddress ATExecDropNotNull (Relation rel, const char *colName, LOCKMODE lockmode)
 
static void ATPrepSetNotNull (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static ObjectAddress ATExecSetNotNull (AlteredTableInfo *tab, Relation rel, const char *colName, LOCKMODE lockmode)
 
static void ATExecCheckNotNull (AlteredTableInfo *tab, Relation rel, const char *colName, LOCKMODE lockmode)
 
static bool NotNullImpliedByRelConstraints (Relation rel, Form_pg_attribute attr)
 
static bool ConstraintImpliedByRelConstraint (Relation scanrel, List *testConstraint, List *provenConstraint)
 
static ObjectAddress ATExecColumnDefault (Relation rel, const char *colName, Node *newDefault, LOCKMODE lockmode)
 
static ObjectAddress ATExecCookedColumnDefault (Relation rel, AttrNumber attnum, Node *newDefault)
 
static ObjectAddress ATExecAddIdentity (Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
 
static ObjectAddress ATExecSetIdentity (Relation rel, const char *colName, Node *def, LOCKMODE lockmode, bool recurse, bool recursing)
 
static ObjectAddress ATExecDropIdentity (Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode, bool recurse, bool recursing)
 
static ObjectAddress ATExecSetExpression (AlteredTableInfo *tab, Relation rel, const char *colName, Node *newExpr, LOCKMODE lockmode)
 
static void ATPrepDropExpression (Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
 
static ObjectAddress ATExecDropExpression (Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetStatistics (Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetOptions (Relation rel, const char *colName, Node *options, bool isReset, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetStorage (Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
 
static void ATPrepDropColumn (List **wqueue, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static ObjectAddress ATExecDropColumn (List **wqueue, Relation rel, const char *colName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode, ObjectAddresses *addrs)
 
static ObjectAddress ATExecAddIndex (AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
 
static ObjectAddress ATExecAddStatistics (AlteredTableInfo *tab, Relation rel, CreateStatsStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
 
static ObjectAddress ATExecAddConstraint (List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *newConstraint, bool recurse, bool is_readd, LOCKMODE lockmode)
 
static char * ChooseForeignKeyConstraintNameAddition (List *colnames)
 
static ObjectAddress ATExecAddIndexConstraint (AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, LOCKMODE lockmode)
 
static ObjectAddress ATAddCheckConstraint (List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
 
static ObjectAddress ATAddForeignKeyConstraint (List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, bool recurse, bool recursing, LOCKMODE lockmode)
 
static ObjectAddress addFkRecurseReferenced (List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, Oid parentDelTrigger, Oid parentUpdTrigger)
 
static void validateFkOnDeleteSetColumns (int numfks, const int16 *fkattnums, int numfksetcols, const int16 *fksetcolsattnums, List *fksetcols)
 
static void addFkRecurseReferencing (List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, LOCKMODE lockmode, Oid parentInsTrigger, Oid parentUpdTrigger)
 
static void CloneForeignKeyConstraints (List **wqueue, Relation parentRel, Relation partitionRel)
 
static void CloneFkReferenced (Relation parentRel, Relation partitionRel)
 
static void CloneFkReferencing (List **wqueue, Relation parentRel, Relation partRel)
 
static void createForeignKeyCheckTriggers (Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
 
static void createForeignKeyActionTriggers (Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
 
static bool tryAttachPartitionForeignKey (ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop, Oid parentInsTrigger, Oid parentUpdTrigger, Relation trigrel)
 
static void GetForeignKeyActionTriggers (Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *deleteTriggerOid, Oid *updateTriggerOid)
 
static void GetForeignKeyCheckTriggers (Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *insertTriggerOid, Oid *updateTriggerOid)
 
static void ATExecDropConstraint (Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode)
 
static void ATPrepAlterColumnType (List **wqueue, AlteredTableInfo *tab, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static bool ATColumnChangeRequiresRewrite (Node *expr, AttrNumber varattno)
 
static ObjectAddress ATExecAlterColumnType (AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static void RememberAllDependentForRebuilding (AlteredTableInfo *tab, AlterTableType subtype, Relation rel, AttrNumber attnum, const char *colName)
 
static void RememberConstraintForRebuilding (Oid conoid, AlteredTableInfo *tab)
 
static void RememberIndexForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
static void RememberStatisticsForRebuilding (Oid stxoid, AlteredTableInfo *tab)
 
static void ATPostAlterTypeCleanup (List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
 
static void ATPostAlterTypeParse (Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, List **wqueue, LOCKMODE lockmode, bool rewrite)
 
static void RebuildConstraintComment (AlteredTableInfo *tab, AlterTablePass pass, Oid objid, Relation rel, List *domname, const char *conname)
 
static void TryReuseIndex (Oid oldId, IndexStmt *stmt)
 
static void TryReuseForeignKey (Oid oldId, Constraint *con)
 
static ObjectAddress ATExecAlterColumnGenericOptions (Relation rel, const char *colName, List *options, LOCKMODE lockmode)
 
static void change_owner_fix_column_acls (Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
 
static void change_owner_recurse_to_sequences (Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
 
static ObjectAddress ATExecClusterOn (Relation rel, const char *indexName, LOCKMODE lockmode)
 
static void ATExecDropCluster (Relation rel, LOCKMODE lockmode)
 
static void ATPrepSetAccessMethod (AlteredTableInfo *tab, Relation rel, const char *amname)
 
static void ATExecSetAccessMethodNoStorage (Relation rel, Oid newAccessMethodId)
 
static bool ATPrepChangePersistence (Relation rel, bool toLogged)
 
static void ATPrepSetTableSpace (AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
 
static void ATExecSetTableSpace (Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 
static void ATExecSetTableSpaceNoStorage (Relation rel, Oid newTableSpace)
 
static void ATExecSetRelOptions (Relation rel, List *defList, AlterTableType operation, LOCKMODE lockmode)
 
static void ATExecEnableDisableTrigger (Relation rel, const char *trigname, char fires_when, bool skip_system, bool recurse, LOCKMODE lockmode)
 
static void ATExecEnableDisableRule (Relation rel, const char *rulename, char fires_when, LOCKMODE lockmode)
 
static void ATPrepAddInherit (Relation child_rel)
 
static ObjectAddress ATExecAddInherit (Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
 
static ObjectAddress ATExecDropInherit (Relation rel, RangeVar *parent, LOCKMODE lockmode)
 
static void drop_parent_dependency (Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
 
static ObjectAddress ATExecAddOf (Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
 
static void ATExecDropOf (Relation rel, LOCKMODE lockmode)
 
static void ATExecReplicaIdentity (Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
 
static void ATExecGenericOptions (Relation rel, List *options)
 
static void ATExecSetRowSecurity (Relation rel, bool rls)
 
static void ATExecForceNoForceRowSecurity (Relation rel, bool force_rls)
 
static ObjectAddress ATExecSetCompression (Relation rel, const char *column, Node *newValue, LOCKMODE lockmode)
 
static void index_copy_data (Relation rel, RelFileLocator newrlocator)
 
static const char * storage_name (char c)
 
static void RangeVarCallbackForDropRelation (const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
 
static void RangeVarCallbackForAlterRelation (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
static PartitionSpectransformPartitionSpec (Relation rel, PartitionSpec *partspec)
 
static void ComputePartitionAttrs (ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, PartitionStrategy strategy)
 
static void CreateInheritance (Relation child_rel, Relation parent_rel, bool ispartition)
 
static void RemoveInheritance (Relation child_rel, Relation parent_rel, bool expect_detached)
 
static ObjectAddress ATExecAttachPartition (List **wqueue, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
 
static void AttachPartitionEnsureIndexes (List **wqueue, Relation rel, Relation attachrel)
 
static void QueuePartitionConstraintValidation (List **wqueue, Relation scanrel, List *partConstraint, bool validate_default)
 
static void CloneRowTriggersToPartition (Relation parent, Relation partition)
 
static void DetachAddConstraintIfNeeded (List **wqueue, Relation partRel)
 
static void DropClonedTriggersFromPartition (Oid partitionId)
 
static ObjectAddress ATExecDetachPartition (List **wqueue, AlteredTableInfo *tab, Relation rel, RangeVar *name, bool concurrent)
 
static void DetachPartitionFinalize (Relation rel, Relation partRel, bool concurrent, Oid defaultPartOid)
 
static ObjectAddress ATExecDetachPartitionFinalize (Relation rel, RangeVar *name)
 
static ObjectAddress ATExecAttachPartitionIdx (List **wqueue, Relation parentIdx, RangeVar *name)
 
static void validatePartitionedIndex (Relation partedIdx, Relation partedTbl)
 
static void refuseDupeIndexAttach (Relation parentIdx, Relation partIdx, Relation partitionTbl)
 
static ListGetParentedForeignKeyRefs (Relation partition)
 
static void ATDetachCheckNoForeignKeyRefs (Relation partition)
 
static char GetAttributeCompression (Oid atttypid, const char *compression)
 
static char GetAttributeStorage (Oid atttypid, const char *storagemode)
 
static void ATExecSplitPartition (List **wqueue, AlteredTableInfo *tab, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
 
static void ATExecMergePartitions (List **wqueue, AlteredTableInfo *tab, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
 
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 attachPartitionTable (List **wqueue, Relation rel, Relation attachrel, PartitionBoundSpec *bound)
 
static void RangeVarCallbackForAttachIndex (const RangeVar *rv, Oid relOid, Oid oldRelOid, void *arg)
 
static SplitPartitionContextcreateSplitPartitionContext (Relation partRel)
 
static void deleteSplitPartitionContext (SplitPartitionContext *pc, int ti_options)
 
static void moveSplitTableRows (Relation rel, Relation splitRel, List *partlist, List *newPartRels, Oid defaultPartOid)
 
static Relation createPartitionTable (RangeVar *newPartName, Relation modelRel, AlterTableUtilityContext *context)
 
static void moveMergedTablesRows (Relation rel, List *mergingPartitionsList, Relation newPartRel)
 

Variables

static Liston_commits = NIL
 
static const struct dropmsgstrings dropmsgstringarray []
 

Macro Definition Documentation

◆ AT_NUM_PASSES

#define AT_NUM_PASSES   (AT_PASS_MISC + 1)

Definition at line 164 of file tablecmds.c.

◆ ATT_COMPOSITE_TYPE

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 329 of file tablecmds.c.

◆ ATT_FOREIGN_TABLE

#define ATT_FOREIGN_TABLE   0x0020

Definition at line 330 of file tablecmds.c.

◆ ATT_INDEX

#define ATT_INDEX   0x0008

Definition at line 328 of file tablecmds.c.

◆ ATT_MATVIEW

#define ATT_MATVIEW   0x0004

Definition at line 327 of file tablecmds.c.

◆ ATT_PARTITIONED_INDEX

#define ATT_PARTITIONED_INDEX   0x0040

Definition at line 331 of file tablecmds.c.

◆ ATT_SEQUENCE

#define ATT_SEQUENCE   0x0080

Definition at line 332 of file tablecmds.c.

◆ ATT_TABLE

#define ATT_TABLE   0x0001

Definition at line 325 of file tablecmds.c.

◆ ATT_VIEW

#define ATT_VIEW   0x0002

Definition at line 326 of file tablecmds.c.

◆ child_dependency_type

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

Definition at line 353 of file tablecmds.c.

Typedef Documentation

◆ AlteredTableInfo

◆ AlterTablePass

◆ ForeignTruncateInfo

◆ NewColumnValue

◆ NewConstraint

typedef struct NewConstraint NewConstraint

◆ OnCommitItem

typedef struct OnCommitItem OnCommitItem

◆ SplitPartitionContext

Enumeration Type Documentation

◆ AlterTablePass

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

Definition at line 146 of file tablecmds.c.

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

Function Documentation

◆ add_column_collation_dependency()

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

Definition at line 7484 of file tablecmds.c.

7485 {
7486  ObjectAddress myself,
7487  referenced;
7488 
7489  /* We know the default collation is pinned, so don't bother recording it */
7490  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7491  {
7492  myself.classId = RelationRelationId;
7493  myself.objectId = relid;
7494  myself.objectSubId = attnum;
7495  referenced.classId = CollationRelationId;
7496  referenced.objectId = collid;
7497  referenced.objectSubId = 0;
7498  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7499  }
7500 }
#define OidIsValid(objectId)
Definition: c.h:775
Oid collid
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int16 attnum
Definition: pg_attribute.h:74
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

◆ add_column_datatype_dependency()

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

Definition at line 7466 of file tablecmds.c.

7467 {
7468  ObjectAddress myself,
7469  referenced;
7470 
7471  myself.classId = RelationRelationId;
7472  myself.objectId = relid;
7473  myself.objectSubId = attnum;
7474  referenced.classId = TypeRelationId;
7475  referenced.objectId = typid;
7476  referenced.objectSubId = 0;
7477  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7478 }

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

◆ addFkRecurseReferenced()

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

Definition at line 10069 of file tablecmds.c.

10077 {
10078  ObjectAddress address;
10079  Oid constrOid;
10080  char *conname;
10081  bool conislocal;
10082  int coninhcount;
10083  bool connoinherit;
10084  Oid deleteTriggerOid,
10085  updateTriggerOid;
10086 
10087  /*
10088  * Verify relkind for each referenced partition. At the top level, this
10089  * is redundant with a previous check, but we need it when recursing.
10090  */
10091  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
10092  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
10093  ereport(ERROR,
10094  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10095  errmsg("referenced relation \"%s\" is not a table",
10096  RelationGetRelationName(pkrel))));
10097 
10098  /*
10099  * Caller supplies us with a constraint name; however, it may be used in
10100  * this partition, so come up with a different one in that case.
10101  */
10103  RelationGetRelid(rel),
10104  fkconstraint->conname))
10107  "fkey",
10108  RelationGetNamespace(rel), NIL);
10109  else
10110  conname = fkconstraint->conname;
10111 
10112  if (OidIsValid(parentConstr))
10113  {
10114  conislocal = false;
10115  coninhcount = 1;
10116  connoinherit = false;
10117  }
10118  else
10119  {
10120  conislocal = true;
10121  coninhcount = 0;
10122 
10123  /*
10124  * always inherit for partitioned tables, never for legacy inheritance
10125  */
10126  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
10127  }
10128 
10129  /*
10130  * Record the FK constraint in pg_constraint.
10131  */
10132  constrOid = CreateConstraintEntry(conname,
10133  RelationGetNamespace(rel),
10134  CONSTRAINT_FOREIGN,
10135  fkconstraint->deferrable,
10136  fkconstraint->initdeferred,
10137  fkconstraint->initially_valid,
10138  parentConstr,
10139  RelationGetRelid(rel),
10140  fkattnum,
10141  numfks,
10142  numfks,
10143  InvalidOid, /* not a domain constraint */
10144  indexOid,
10145  RelationGetRelid(pkrel),
10146  pkattnum,
10147  pfeqoperators,
10148  ppeqoperators,
10149  ffeqoperators,
10150  numfks,
10151  fkconstraint->fk_upd_action,
10152  fkconstraint->fk_del_action,
10153  fkdelsetcols,
10154  numfkdelsetcols,
10155  fkconstraint->fk_matchtype,
10156  NULL, /* no exclusion constraint */
10157  NULL, /* no check constraint */
10158  NULL,
10159  conislocal, /* islocal */
10160  coninhcount, /* inhcount */
10161  connoinherit, /* conNoInherit */
10162  false); /* is_internal */
10163 
10164  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10165 
10166  /*
10167  * Mark the child constraint as part of the parent constraint; it must not
10168  * be dropped on its own. (This constraint is deleted when the partition
10169  * is detached, but a special check needs to occur that the partition
10170  * contains no referenced values.)
10171  */
10172  if (OidIsValid(parentConstr))
10173  {
10174  ObjectAddress referenced;
10175 
10176  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
10177  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
10178  }
10179 
10180  /* make new constraint visible, in case we add more */
10182 
10183  /*
10184  * Create the action triggers that enforce the constraint.
10185  */
10187  fkconstraint,
10188  constrOid, indexOid,
10189  parentDelTrigger, parentUpdTrigger,
10190  &deleteTriggerOid, &updateTriggerOid);
10191 
10192  /*
10193  * If the referenced table is partitioned, recurse on ourselves to handle
10194  * each partition. We need one pg_constraint row created for each
10195  * partition in addition to the pg_constraint row for the parent table.
10196  */
10197  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10198  {
10199  PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
10200 
10201  for (int i = 0; i < pd->nparts; i++)
10202  {
10203  Relation partRel;
10204  AttrMap *map;
10205  AttrNumber *mapped_pkattnum;
10206  Oid partIndexId;
10207 
10208  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
10209 
10210  /*
10211  * Map the attribute numbers in the referenced side of the FK
10212  * definition to match the partition's column layout.
10213  */
10215  RelationGetDescr(pkrel),
10216  false);
10217  if (map)
10218  {
10219  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
10220  for (int j = 0; j < numfks; j++)
10221  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
10222  }
10223  else
10224  mapped_pkattnum = pkattnum;
10225 
10226  /* do the deed */
10227  partIndexId = index_get_partition(partRel, indexOid);
10228  if (!OidIsValid(partIndexId))
10229  elog(ERROR, "index for %u not found in partition %s",
10230  indexOid, RelationGetRelationName(partRel));
10231  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
10232  partIndexId, constrOid, numfks,
10233  mapped_pkattnum, fkattnum,
10234  pfeqoperators, ppeqoperators, ffeqoperators,
10235  numfkdelsetcols, fkdelsetcols,
10236  old_check_ok,
10237  deleteTriggerOid, updateTriggerOid);
10238 
10239  /* Done -- clean up (but keep the lock) */
10240  table_close(partRel, NoLock);
10241  if (map)
10242  {
10243  pfree(mapped_pkattnum);
10244  free_attrmap(map);
10245  }
10246  }
10247  }
10248 
10249  return address;
10250 }
void free_attrmap(AttrMap *map)
Definition: attmap.c:56
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:263
int16 AttrNumber
Definition: attnum.h:21
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int errcode(int sqlerrcode)
Definition: elog.c:857
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
int j
Definition: isn.c:74
int i
Definition: isn.c:73
#define NoLock
Definition: lockdefs.h:34
#define ShareRowExclusiveLock
Definition: lockdefs.h:41
void pfree(void *pointer)
Definition: mcxt.c:1520
void * palloc(Size size)
Definition: mcxt.c:1316
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:71
Oid index_get_partition(Relation partition, Oid indexId)
Definition: partition.c:176
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:48
@ CONSTRAINT_RELATION
#define NIL
Definition: pg_list.h:68
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetDescr(relation)
Definition: rel.h:531
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationGetNamespace(relation)
Definition: rel.h:546
Definition: attmap.h:35
AttrNumber * attnums
Definition: attmap.h:36
bool initdeferred
Definition: parsenodes.h:2739
char fk_upd_action
Definition: parsenodes.h:2770
char fk_matchtype
Definition: parsenodes.h:2769
bool initially_valid
Definition: parsenodes.h:2741
bool deferrable
Definition: parsenodes.h:2738
char * conname
Definition: parsenodes.h:2737
char fk_del_action
Definition: parsenodes.h:2771
List * fk_attrs
Definition: parsenodes.h:2767
Form_pg_class rd_rel
Definition: rel.h:111
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:9403
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12272
static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, Oid parentDelTrigger, Oid parentUpdTrigger)
Definition: tablecmds.c:10069
void CommandCounterIncrement(void)
Definition: xact.c:1097

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

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferenced().

◆ addFkRecurseReferencing()

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

Definition at line 10289 of file tablecmds.c.

10296 {
10297  Oid insertTriggerOid,
10298  updateTriggerOid;
10299 
10300  Assert(OidIsValid(parentConstr));
10301 
10302  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
10303  ereport(ERROR,
10304  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10305  errmsg("foreign key constraints are not supported on foreign tables")));
10306 
10307  /*
10308  * Add the check triggers to it and, if necessary, schedule it to be
10309  * checked in Phase 3.
10310  *
10311  * If the relation is partitioned, drill down to do it to its partitions.
10312  */
10314  RelationGetRelid(pkrel),
10315  fkconstraint,
10316  parentConstr,
10317  indexOid,
10318  parentInsTrigger, parentUpdTrigger,
10319  &insertTriggerOid, &updateTriggerOid);
10320 
10321  if (rel->rd_rel->relkind == RELKIND_RELATION)
10322  {
10323  /*
10324  * Tell Phase 3 to check that the constraint is satisfied by existing
10325  * rows. We can skip this during table creation, when requested
10326  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
10327  * and when we're recreating a constraint following a SET DATA TYPE
10328  * operation that did not impugn its validity.
10329  */
10330  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
10331  {
10332  NewConstraint *newcon;
10333  AlteredTableInfo *tab;
10334 
10335  tab = ATGetQueueEntry(wqueue, rel);
10336 
10337  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
10338  newcon->name = get_constraint_name(parentConstr);
10339  newcon->contype = CONSTR_FOREIGN;
10340  newcon->refrelid = RelationGetRelid(pkrel);
10341  newcon->refindid = indexOid;
10342  newcon->conid = parentConstr;
10343  newcon->qual = (Node *) fkconstraint;
10344 
10345  tab->constraints = lappend(tab->constraints, newcon);
10346  }
10347  }
10348  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10349  {
10350  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
10351  Relation trigrel;
10352 
10353  /*
10354  * Triggers of the foreign keys will be manipulated a bunch of times
10355  * in the loop below. To avoid repeatedly opening/closing the trigger
10356  * catalog relation, we open it here and pass it to the subroutines
10357  * called below.
10358  */
10359  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
10360 
10361  /*
10362  * Recurse to take appropriate action on each partition; either we
10363  * find an existing constraint to reparent to ours, or we create a new
10364  * one.
10365  */
10366  for (int i = 0; i < pd->nparts; i++)
10367  {
10368  Oid partitionId = pd->oids[i];
10369  Relation partition = table_open(partitionId, lockmode);
10370  List *partFKs;
10371  AttrMap *attmap;
10372  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
10373  bool attached;
10374  char *conname;
10375  Oid constrOid;
10376  ObjectAddress address,
10377  referenced;
10378  ListCell *cell;
10379 
10380  CheckAlterTableIsSafe(partition);
10381 
10382  attmap = build_attrmap_by_name(RelationGetDescr(partition),
10383  RelationGetDescr(rel),
10384  false);
10385  for (int j = 0; j < numfks; j++)
10386  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
10387 
10388  /* Check whether an existing constraint can be repurposed */
10389  partFKs = copyObject(RelationGetFKeyList(partition));
10390  attached = false;
10391  foreach(cell, partFKs)
10392  {
10393  ForeignKeyCacheInfo *fk;
10394 
10395  fk = lfirst_node(ForeignKeyCacheInfo, cell);
10397  partitionId,
10398  parentConstr,
10399  numfks,
10400  mapped_fkattnum,
10401  pkattnum,
10402  pfeqoperators,
10403  insertTriggerOid,
10404  updateTriggerOid,
10405  trigrel))
10406  {
10407  attached = true;
10408  break;
10409  }
10410  }
10411  if (attached)
10412  {
10413  table_close(partition, NoLock);
10414  continue;
10415  }
10416 
10417  /*
10418  * No luck finding a good constraint to reuse; create our own.
10419  */
10421  RelationGetRelid(partition),
10422  fkconstraint->conname))
10423  conname = ChooseConstraintName(RelationGetRelationName(partition),
10425  "fkey",
10426  RelationGetNamespace(partition), NIL);
10427  else
10428  conname = fkconstraint->conname;
10429  constrOid =
10430  CreateConstraintEntry(conname,
10431  RelationGetNamespace(partition),
10432  CONSTRAINT_FOREIGN,
10433  fkconstraint->deferrable,
10434  fkconstraint->initdeferred,
10435  fkconstraint->initially_valid,
10436  parentConstr,
10437  partitionId,
10438  mapped_fkattnum,
10439  numfks,
10440  numfks,
10441  InvalidOid,
10442  indexOid,
10443  RelationGetRelid(pkrel),
10444  pkattnum,
10445  pfeqoperators,
10446  ppeqoperators,
10447  ffeqoperators,
10448  numfks,
10449  fkconstraint->fk_upd_action,
10450  fkconstraint->fk_del_action,
10451  fkdelsetcols,
10452  numfkdelsetcols,
10453  fkconstraint->fk_matchtype,
10454  NULL,
10455  NULL,
10456  NULL,
10457  false,
10458  1,
10459  false,
10460  false);
10461 
10462  /*
10463  * Give this constraint partition-type dependencies on the parent
10464  * constraint as well as the table.
10465  */
10466  ObjectAddressSet(address, ConstraintRelationId, constrOid);
10467  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
10468  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
10469  ObjectAddressSet(referenced, RelationRelationId, partitionId);
10470  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
10471 
10472  /* Make all this visible before recursing */
10474 
10475  /* call ourselves to finalize the creation and we're done */
10476  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
10477  indexOid,
10478  constrOid,
10479  numfks,
10480  pkattnum,
10481  mapped_fkattnum,
10482  pfeqoperators,
10483  ppeqoperators,
10484  ffeqoperators,
10485  numfkdelsetcols,
10486  fkdelsetcols,
10487  old_check_ok,
10488  lockmode,
10489  insertTriggerOid,
10490  updateTriggerOid);
10491 
10492  table_close(partition, NoLock);
10493  }
10494 
10495  table_close(trigrel, RowExclusiveLock);
10496  }
10497 }
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:177
#define Assert(condition)
Definition: c.h:858
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
List * lappend(List *list, void *datum)
Definition: list.c:339
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1081
void * palloc0(Size size)
Definition: mcxt.c:1346
#define copyObject(obj)
Definition: nodes.h:224
@ CONSTR_FOREIGN
Definition: parsenodes.h:2714
#define INDEX_MAX_KEYS
#define lfirst_node(type, lc)
Definition: pg_list.h:176
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4691
List * constraints
Definition: tablecmds.c:185
bool skip_validation
Definition: parsenodes.h:2740
Definition: pg_list.h:54
char * name
Definition: tablecmds.c:214
ConstrType contype
Definition: tablecmds.c:215
Node * qual
Definition: tablecmds.c:219
Definition: nodes.h:129
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:6368
static void CheckAlterTableIsSafe(Relation rel)
Definition: tablecmds.c:4284
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:11017
static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, LOCKMODE lockmode, Oid parentInsTrigger, Oid parentUpdTrigger)
Definition: tablecmds.c:10289
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:12407

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

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferencing().

◆ alter_table_type_to_string()

static const char* alter_table_type_to_string ( AlterTableType  cmdtype)
static

Definition at line 6402 of file tablecmds.c.

6403 {
6404  switch (cmdtype)
6405  {
6406  case AT_AddColumn:
6407  case AT_AddColumnToView:
6408  return "ADD COLUMN";
6409  case AT_ColumnDefault:
6411  return "ALTER COLUMN ... SET DEFAULT";
6412  case AT_DropNotNull:
6413  return "ALTER COLUMN ... DROP NOT NULL";
6414  case AT_SetNotNull:
6415  return "ALTER COLUMN ... SET NOT NULL";
6416  case AT_SetExpression:
6417  return "ALTER COLUMN ... SET EXPRESSION";
6418  case AT_DropExpression:
6419  return "ALTER COLUMN ... DROP EXPRESSION";
6420  case AT_CheckNotNull:
6421  return NULL; /* not real grammar */
6422  case AT_SetStatistics:
6423  return "ALTER COLUMN ... SET STATISTICS";
6424  case AT_SetOptions:
6425  return "ALTER COLUMN ... SET";
6426  case AT_ResetOptions:
6427  return "ALTER COLUMN ... RESET";
6428  case AT_SetStorage:
6429  return "ALTER COLUMN ... SET STORAGE";
6430  case AT_SetCompression:
6431  return "ALTER COLUMN ... SET COMPRESSION";
6432  case AT_DropColumn:
6433  return "DROP COLUMN";
6434  case AT_AddIndex:
6435  case AT_ReAddIndex:
6436  return NULL; /* not real grammar */
6437  case AT_AddConstraint:
6438  case AT_ReAddConstraint:
6440  case AT_AddIndexConstraint:
6441  return "ADD CONSTRAINT";
6442  case AT_AlterConstraint:
6443  return "ALTER CONSTRAINT";
6444  case AT_ValidateConstraint:
6445  return "VALIDATE CONSTRAINT";
6446  case AT_DropConstraint:
6447  return "DROP CONSTRAINT";
6448  case AT_ReAddComment:
6449  return NULL; /* not real grammar */
6450  case AT_AlterColumnType:
6451  return "ALTER COLUMN ... SET DATA TYPE";
6453  return "ALTER COLUMN ... OPTIONS";
6454  case AT_ChangeOwner:
6455  return "OWNER TO";
6456  case AT_ClusterOn:
6457  return "CLUSTER ON";
6458  case AT_DropCluster:
6459  return "SET WITHOUT CLUSTER";
6460  case AT_SetAccessMethod:
6461  return "SET ACCESS METHOD";
6462  case AT_SetLogged:
6463  return "SET LOGGED";
6464  case AT_SetUnLogged:
6465  return "SET UNLOGGED";
6466  case AT_DropOids:
6467  return "SET WITHOUT OIDS";
6468  case AT_SetTableSpace:
6469  return "SET TABLESPACE";
6470  case AT_SetRelOptions:
6471  return "SET";
6472  case AT_ResetRelOptions:
6473  return "RESET";
6474  case AT_ReplaceRelOptions:
6475  return NULL; /* not real grammar */
6476  case AT_EnableTrig:
6477  return "ENABLE TRIGGER";
6478  case AT_EnableAlwaysTrig:
6479  return "ENABLE ALWAYS TRIGGER";
6480  case AT_EnableReplicaTrig:
6481  return "ENABLE REPLICA TRIGGER";
6482  case AT_DisableTrig:
6483  return "DISABLE TRIGGER";
6484  case AT_EnableTrigAll:
6485  return "ENABLE TRIGGER ALL";
6486  case AT_DisableTrigAll:
6487  return "DISABLE TRIGGER ALL";
6488  case AT_EnableTrigUser:
6489  return "ENABLE TRIGGER USER";
6490  case AT_DisableTrigUser:
6491  return "DISABLE TRIGGER USER";
6492  case AT_EnableRule:
6493  return "ENABLE RULE";
6494  case AT_EnableAlwaysRule:
6495  return "ENABLE ALWAYS RULE";
6496  case AT_EnableReplicaRule:
6497  return "ENABLE REPLICA RULE";
6498  case AT_DisableRule:
6499  return "DISABLE RULE";
6500  case AT_AddInherit:
6501  return "INHERIT";
6502  case AT_DropInherit:
6503  return "NO INHERIT";
6504  case AT_AddOf:
6505  return "OF";
6506  case AT_DropOf:
6507  return "NOT OF";
6508  case AT_ReplicaIdentity:
6509  return "REPLICA IDENTITY";
6510  case AT_EnableRowSecurity:
6511  return "ENABLE ROW SECURITY";
6512  case AT_DisableRowSecurity:
6513  return "DISABLE ROW SECURITY";
6514  case AT_ForceRowSecurity:
6515  return "FORCE ROW SECURITY";
6516  case AT_NoForceRowSecurity:
6517  return "NO FORCE ROW SECURITY";
6518  case AT_GenericOptions:
6519  return "OPTIONS";
6520  case AT_AttachPartition:
6521  return "ATTACH PARTITION";
6522  case AT_DetachPartition:
6523  return "DETACH PARTITION";
6525  return "DETACH PARTITION ... FINALIZE";
6526  case AT_SplitPartition:
6527  return "SPLIT PARTITION";
6528  case AT_MergePartitions:
6529  return "MERGE PARTITIONS";
6530  case AT_AddIdentity:
6531  return "ALTER COLUMN ... ADD IDENTITY";
6532  case AT_SetIdentity:
6533  return "ALTER COLUMN ... SET";
6534  case AT_DropIdentity:
6535  return "ALTER COLUMN ... DROP IDENTITY";
6536  case AT_ReAddStatistics:
6537  return NULL; /* not real grammar */
6538  }
6539 
6540  return NULL;
6541 }
@ AT_AddIndexConstraint
Definition: parsenodes.h:2375
@ AT_MergePartitions
Definition: parsenodes.h:2417
@ AT_DropOf
Definition: parsenodes.h:2406
@ AT_CheckNotNull
Definition: parsenodes.h:2361
@ AT_SetOptions
Definition: parsenodes.h:2363
@ AT_DropIdentity
Definition: parsenodes.h:2420
@ AT_DisableTrigUser
Definition: parsenodes.h:2398
@ AT_DropNotNull
Definition: parsenodes.h:2357
@ AT_AddOf
Definition: parsenodes.h:2405
@ AT_ResetOptions
Definition: parsenodes.h:2364
@ AT_ReplicaIdentity
Definition: parsenodes.h:2407
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2390
@ AT_EnableRowSecurity
Definition: parsenodes.h:2408
@ AT_AddColumnToView
Definition: parsenodes.h:2354
@ AT_ResetRelOptions
Definition: parsenodes.h:2389
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2393
@ AT_DropOids
Definition: parsenodes.h:2385
@ AT_SetIdentity
Definition: parsenodes.h:2419
@ AT_ReAddStatistics
Definition: parsenodes.h:2421
@ AT_SetUnLogged
Definition: parsenodes.h:2384
@ AT_DisableTrig
Definition: parsenodes.h:2394
@ AT_SetCompression
Definition: parsenodes.h:2366
@ AT_DropExpression
Definition: parsenodes.h:2360
@ AT_AddIndex
Definition: parsenodes.h:2368
@ AT_EnableReplicaRule
Definition: parsenodes.h:2401
@ AT_ReAddIndex
Definition: parsenodes.h:2369
@ AT_DropConstraint
Definition: parsenodes.h:2376
@ AT_SetNotNull
Definition: parsenodes.h:2358
@ AT_ClusterOn
Definition: parsenodes.h:2381
@ AT_AddIdentity
Definition: parsenodes.h:2418
@ AT_ForceRowSecurity
Definition: parsenodes.h:2410
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2400
@ AT_SetAccessMethod
Definition: parsenodes.h:2386
@ AT_AlterColumnType
Definition: parsenodes.h:2378
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2415
@ AT_AddInherit
Definition: parsenodes.h:2403
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2372
@ AT_EnableTrig
Definition: parsenodes.h:2391
@ AT_DropColumn
Definition: parsenodes.h:2367
@ AT_ReAddComment
Definition: parsenodes.h:2377
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2379
@ AT_DisableTrigAll
Definition: parsenodes.h:2396
@ AT_EnableRule
Definition: parsenodes.h:2399
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2411
@ AT_DetachPartition
Definition: parsenodes.h:2414
@ AT_SetStatistics
Definition: parsenodes.h:2362
@ AT_AttachPartition
Definition: parsenodes.h:2413
@ AT_AddConstraint
Definition: parsenodes.h:2370
@ AT_DropInherit
Definition: parsenodes.h:2404
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2392
@ AT_SetLogged
Definition: parsenodes.h:2383
@ AT_SetStorage
Definition: parsenodes.h:2365
@ AT_DisableRule
Definition: parsenodes.h:2402
@ AT_DisableRowSecurity
Definition: parsenodes.h:2409
@ AT_SetRelOptions
Definition: parsenodes.h:2388
@ AT_ChangeOwner
Definition: parsenodes.h:2380
@ AT_EnableTrigUser
Definition: parsenodes.h:2397
@ AT_SetExpression
Definition: parsenodes.h:2359
@ AT_ReAddConstraint
Definition: parsenodes.h:2371
@ AT_SetTableSpace
Definition: parsenodes.h:2387
@ AT_GenericOptions
Definition: parsenodes.h:2412
@ AT_ColumnDefault
Definition: parsenodes.h:2355
@ AT_CookedColumnDefault
Definition: parsenodes.h:2356
@ AT_AlterConstraint
Definition: parsenodes.h:2373
@ AT_EnableTrigAll
Definition: parsenodes.h:2395
@ AT_SplitPartition
Definition: parsenodes.h:2416
@ AT_DropCluster
Definition: parsenodes.h:2382
@ AT_ValidateConstraint
Definition: parsenodes.h:2374
@ AT_AddColumn
Definition: parsenodes.h:2353

References AT_AddColumn, AT_AddColumnToView, AT_AddConstraint, AT_AddIdentity, AT_AddIndex, AT_AddIndexConstraint, AT_AddInherit, AT_AddOf, AT_AlterColumnGenericOptions, AT_AlterColumnType, AT_AlterConstraint, AT_AttachPartition, AT_ChangeOwner, AT_CheckNotNull, AT_ClusterOn, AT_ColumnDefault, AT_CookedColumnDefault, AT_DetachPartition, AT_DetachPartitionFinalize, AT_DisableRowSecurity, AT_DisableRule, AT_DisableTrig, AT_DisableTrigAll, AT_DisableTrigUser, AT_DropCluster, AT_DropColumn, AT_DropConstraint, AT_DropExpression, AT_DropIdentity, AT_DropInherit, AT_DropNotNull, AT_DropOf, AT_DropOids, AT_EnableAlwaysRule, AT_EnableAlwaysTrig, AT_EnableReplicaRule, AT_EnableReplicaTrig, AT_EnableRowSecurity, AT_EnableRule, AT_EnableTrig, AT_EnableTrigAll, AT_EnableTrigUser, AT_ForceRowSecurity, AT_GenericOptions, AT_MergePartitions, 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, AT_SplitPartition, and AT_ValidateConstraint.

Referenced by ATSimplePermissions().

◆ AlterIndexNamespaces()

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

Definition at line 17221 of file tablecmds.c.

17223 {
17224  List *indexList;
17225  ListCell *l;
17226 
17227  indexList = RelationGetIndexList(rel);
17228 
17229  foreach(l, indexList)
17230  {
17231  Oid indexOid = lfirst_oid(l);
17232  ObjectAddress thisobj;
17233 
17234  thisobj.classId = RelationRelationId;
17235  thisobj.objectId = indexOid;
17236  thisobj.objectSubId = 0;
17237 
17238  /*
17239  * Note: currently, the index will not have its own dependency on the
17240  * namespace, so we don't need to do changeDependencyFor(). There's no
17241  * row type in pg_type, either.
17242  *
17243  * XXX this objsMoved test may be pointless -- surely we have a single
17244  * dependency link from a relation to each index?
17245  */
17246  if (!object_address_present(&thisobj, objsMoved))
17247  {
17248  AlterRelationNamespaceInternal(classRel, indexOid,
17249  oldNspOid, newNspOid,
17250  false, objsMoved);
17251  add_exact_object_address(&thisobj, objsMoved);
17252  }
17253  }
17254 
17255  list_free(indexList);
17256 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2591
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2531
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:4800
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17151

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

17155 {
17156  HeapTuple classTup;
17157  Form_pg_class classForm;
17158  ObjectAddress thisobj;
17159  bool already_done = false;
17160 
17161  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
17162  if (!HeapTupleIsValid(classTup))
17163  elog(ERROR, "cache lookup failed for relation %u", relOid);
17164  classForm = (Form_pg_class) GETSTRUCT(classTup);
17165 
17166  Assert(classForm->relnamespace == oldNspOid);
17167 
17168  thisobj.classId = RelationRelationId;
17169  thisobj.objectId = relOid;
17170  thisobj.objectSubId = 0;
17171 
17172  /*
17173  * If the object has already been moved, don't move it again. If it's
17174  * already in the right place, don't move it, but still fire the object
17175  * access hook.
17176  */
17177  already_done = object_address_present(&thisobj, objsMoved);
17178  if (!already_done && oldNspOid != newNspOid)
17179  {
17180  /* check for duplicate name (more friendly than unique-index failure) */
17181  if (get_relname_relid(NameStr(classForm->relname),
17182  newNspOid) != InvalidOid)
17183  ereport(ERROR,
17184  (errcode(ERRCODE_DUPLICATE_TABLE),
17185  errmsg("relation \"%s\" already exists in schema \"%s\"",
17186  NameStr(classForm->relname),
17187  get_namespace_name(newNspOid))));
17188 
17189  /* classTup is a copy, so OK to scribble on */
17190  classForm->relnamespace = newNspOid;
17191 
17192  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
17193 
17194  /* Update dependency on schema if caller said so */
17195  if (hasDependEntry &&
17196  changeDependencyFor(RelationRelationId,
17197  relOid,
17198  NamespaceRelationId,
17199  oldNspOid,
17200  newNspOid) != 1)
17201  elog(ERROR, "could not change schema dependency for relation \"%s\"",
17202  NameStr(classForm->relname));
17203  }
17204  if (!already_done)
17205  {
17206  add_exact_object_address(&thisobj, objsMoved);
17207 
17208  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
17209  }
17210 
17211  heap_freetuple(classTup);
17212 }
#define NameStr(name)
Definition: c.h:746
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1885
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:458
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86

References add_exact_object_address(), Assert, CatalogTupleUpdate(), changeDependencyFor(), ObjectAddress::classId, elog, ereport, errcode(), errmsg(), ERROR, get_namespace_name(), get_relname_relid(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHook, NameStr, object_address_present(), ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, SearchSysCacheCopy1, and HeapTupleData::t_self.

Referenced by AlterIndexNamespaces(), AlterSeqNamespaces(), AlterTableNamespaceInternal(), and AlterTypeNamespaceInternal().

◆ AlterSeqNamespaces()

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

Definition at line 17266 of file tablecmds.c.

17269 {
17270  Relation depRel;
17271  SysScanDesc scan;
17272  ScanKeyData key[2];
17273  HeapTuple tup;
17274 
17275  /*
17276  * SERIAL sequences are those having an auto dependency on one of the
17277  * table's columns (we don't care *which* column, exactly).
17278  */
17279  depRel = table_open(DependRelationId, AccessShareLock);
17280 
17281  ScanKeyInit(&key[0],
17282  Anum_pg_depend_refclassid,
17283  BTEqualStrategyNumber, F_OIDEQ,
17284  ObjectIdGetDatum(RelationRelationId));
17285  ScanKeyInit(&key[1],
17286  Anum_pg_depend_refobjid,
17287  BTEqualStrategyNumber, F_OIDEQ,
17289  /* we leave refobjsubid unspecified */
17290 
17291  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
17292  NULL, 2, key);
17293 
17294  while (HeapTupleIsValid(tup = systable_getnext(scan)))
17295  {
17296  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
17297  Relation seqRel;
17298 
17299  /* skip dependencies other than auto dependencies on columns */
17300  if (depForm->refobjsubid == 0 ||
17301  depForm->classid != RelationRelationId ||
17302  depForm->objsubid != 0 ||
17303  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
17304  continue;
17305 
17306  /* Use relation_open just in case it's an index */
17307  seqRel = relation_open(depForm->objid, lockmode);
17308 
17309  /* skip non-sequence relations */
17310  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
17311  {
17312  /* No need to keep the lock */
17313  relation_close(seqRel, lockmode);
17314  continue;
17315  }
17316 
17317  /* Fix the pg_class and pg_depend entries */
17318  AlterRelationNamespaceInternal(classRel, depForm->objid,
17319  oldNspOid, newNspOid,
17320  true, objsMoved);
17321 
17322  /*
17323  * Sequences used to have entries in pg_type, but no longer do. If we
17324  * ever re-instate that, we'll need to move the pg_type entry to the
17325  * new namespace, too (using AlterTypeNamespaceInternal).
17326  */
17327  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
17328 
17329  /* Now we can close it. Keep the lock till end of transaction. */
17330  relation_close(seqRel, NoLock);
17331  }
17332 
17333  systable_endscan(scan);
17334 
17336 }
@ DEPENDENCY_AUTO
Definition: dependency.h:34
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
#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 4369 of file tablecmds.c.

4371 {
4372  Relation rel;
4373 
4374  /* Caller is required to provide an adequate lock. */
4375  rel = relation_open(context->relid, NoLock);
4376 
4377  CheckAlterTableIsSafe(rel);
4378 
4379  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4380 }
#define stmt
Definition: indent_codes.h:59
tree context
Definition: radixtree.h:1833
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4722

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

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4443 of file tablecmds.c.

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

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

4399 {
4400  Relation rel;
4401  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4402 
4403  rel = relation_open(relid, lockmode);
4404 
4406 
4407  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4408 }
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4443

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4310 of file tablecmds.c.

4311 {
4312  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4313  stmt->missing_ok ? RVR_MISSING_OK : 0,
4315  (void *) stmt);
4316 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:426
@ RVR_MISSING_OK
Definition: namespace.h:72
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:17676

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

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 15221 of file tablecmds.c.

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

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

17044 {
17045  Relation rel;
17046  Oid relid;
17047  Oid oldNspOid;
17048  Oid nspOid;
17049  RangeVar *newrv;
17050  ObjectAddresses *objsMoved;
17051  ObjectAddress myself;
17052 
17054  stmt->missing_ok ? RVR_MISSING_OK : 0,
17056  (void *) stmt);
17057 
17058  if (!OidIsValid(relid))
17059  {
17060  ereport(NOTICE,
17061  (errmsg("relation \"%s\" does not exist, skipping",
17062  stmt->relation->relname)));
17063  return InvalidObjectAddress;
17064  }
17065 
17066  rel = relation_open(relid, NoLock);
17067 
17068  oldNspOid = RelationGetNamespace(rel);
17069 
17070  /* If it's an owned sequence, disallow moving it by itself. */
17071  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
17072  {
17073  Oid tableId;
17074  int32 colId;
17075 
17076  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
17077  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
17078  ereport(ERROR,
17079  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
17080  errmsg("cannot move an owned sequence into another schema"),
17081  errdetail("Sequence \"%s\" is linked to table \"%s\".",
17083  get_rel_name(tableId))));
17084  }
17085 
17086  /* Get and lock schema OID and check its permissions. */
17087  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
17088  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
17089 
17090  /* common checks on switching namespaces */
17091  CheckSetNamespace(oldNspOid, nspOid);
17092 
17093  objsMoved = new_object_addresses();
17094  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
17095  free_object_addresses(objsMoved);
17096 
17097  ObjectAddressSet(myself, RelationRelationId, relid);
17098 
17099  if (oldschema)
17100  *oldschema = oldNspOid;
17101 
17102  /* close rel, but keep lock until commit */
17103  relation_close(rel, NoLock);
17104 
17105  return myself;
17106 }
signed int int32
Definition: c.h:494
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2485
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2771
int errdetail(const char *fmt,...)
Definition: elog.c:1203
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:424
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:724
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3444
const ObjectAddress InvalidObjectAddress
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:829
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17114

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

17116 {
17117  Relation classRel;
17118 
17119  Assert(objsMoved != NULL);
17120 
17121  /* OK, modify the pg_class row and pg_depend entry */
17122  classRel = table_open(RelationRelationId, RowExclusiveLock);
17123 
17124  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
17125  nspOid, true, objsMoved);
17126 
17127  /* Fix the table's row type too, if it has one */
17128  if (OidIsValid(rel->rd_rel->reltype))
17129  AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid,
17130  false, /* isImplicitArray */
17131  false, /* ignoreDependent */
17132  false, /* errorOnTableType */
17133  objsMoved);
17134 
17135  /* Fix other dependent stuff */
17136  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
17137  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
17138  objsMoved, AccessExclusiveLock);
17139  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
17140  false, objsMoved);
17141 
17142  table_close(classRel, RowExclusiveLock);
17143 }
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:17266
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:17221
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:4156

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

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

◆ ATAddCheckConstraint()

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

Definition at line 9445 of file tablecmds.c.

9448 {
9449  List *newcons;
9450  ListCell *lcon;
9451  List *children;
9452  ListCell *child;
9454 
9455  /* At top level, permission check was done in ATPrepCmd, else do it */
9456  if (recursing)
9458 
9459  /*
9460  * Call AddRelationNewConstraints to do the work, making sure it works on
9461  * a copy of the Constraint so transformExpr can't modify the original. It
9462  * returns a list of cooked constraints.
9463  *
9464  * If the constraint ends up getting merged with a pre-existing one, it's
9465  * omitted from the returned list, which is what we want: we do not need
9466  * to do any validation work. That can only happen at child tables,
9467  * though, since we disallow merging at the top level.
9468  */
9469  newcons = AddRelationNewConstraints(rel, NIL,
9470  list_make1(copyObject(constr)),
9471  recursing || is_readd, /* allow_merge */
9472  !recursing, /* is_local */
9473  is_readd, /* is_internal */
9474  NULL); /* queryString not available
9475  * here */
9476 
9477  /* we don't expect more than one constraint here */
9478  Assert(list_length(newcons) <= 1);
9479 
9480  /* Add each to-be-validated constraint to Phase 3's queue */
9481  foreach(lcon, newcons)
9482  {
9483  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
9484 
9485  if (!ccon->skip_validation)
9486  {
9487  NewConstraint *newcon;
9488 
9489  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9490  newcon->name = ccon->name;
9491  newcon->contype = ccon->contype;
9492  newcon->qual = ccon->expr;
9493 
9494  tab->constraints = lappend(tab->constraints, newcon);
9495  }
9496 
9497  /* Save the actually assigned name if it was defaulted */
9498  if (constr->conname == NULL)
9499  constr->conname = ccon->name;
9500 
9501  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
9502  }
9503 
9504  /* At this point we must have a locked-down name to use */
9505  Assert(constr->conname != NULL);
9506 
9507  /* Advance command counter in case same table is visited multiple times */
9509 
9510  /*
9511  * If the constraint got merged with an existing constraint, we're done.
9512  * We mustn't recurse to child tables in this case, because they've
9513  * already got the constraint, and visiting them again would lead to an
9514  * incorrect value for coninhcount.
9515  */
9516  if (newcons == NIL)
9517  return address;
9518 
9519  /*
9520  * If adding a NO INHERIT constraint, no need to find our children.
9521  */
9522  if (constr->is_no_inherit)
9523  return address;
9524 
9525  /*
9526  * Propagate to children as appropriate. Unlike most other ALTER
9527  * routines, we have to do this one level of recursion at a time; we can't
9528  * use find_all_inheritors to do it in one pass.
9529  */
9530  children =
9532 
9533  /*
9534  * Check if ONLY was specified with ALTER TABLE. If so, allow the
9535  * constraint creation only if there are no children currently. Error out
9536  * otherwise.
9537  */
9538  if (!recurse && children != NIL)
9539  ereport(ERROR,
9540  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9541  errmsg("constraint must be added to child tables too")));
9542 
9543  foreach(child, children)
9544  {
9545  Oid childrelid = lfirst_oid(child);
9546  Relation childrel;
9547  AlteredTableInfo *childtab;
9548 
9549  /* find_inheritance_children already got lock */
9550  childrel = table_open(childrelid, NoLock);
9551  CheckAlterTableIsSafe(childrel);
9552 
9553  /* Find or create work queue entry for this table */
9554  childtab = ATGetQueueEntry(wqueue, childrel);
9555 
9556  /* Recurse to child */
9557  ATAddCheckConstraint(wqueue, childtab, childrel,
9558  constr, recurse, true, is_readd, lockmode);
9559 
9560  table_close(childrel, NoLock);
9561  }
9562 
9563  return address;
9564 }
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2250
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:58
static int list_length(const List *l)
Definition: pg_list.h:152
#define list_make1(x1)
Definition: pg_list.h:212
bool is_no_inherit
Definition: parsenodes.h:2742
Oid conoid
Definition: heap.h:38
char * name
Definition: heap.h:39
bool skip_validation
Definition: heap.h:42
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:41
#define ATT_TABLE
Definition: tablecmds.c:325
static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
Definition: tablecmds.c:6551
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:330
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:9445

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

Referenced by ATExecAddConstraint(), and DetachAddConstraintIfNeeded().

◆ ATAddForeignKeyConstraint()

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

Definition at line 9582 of file tablecmds.c.

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

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

Referenced by ATExecAddConstraint().

◆ ATCheckPartitionsNotInUse()

static void ATCheckPartitionsNotInUse ( Relation  rel,
LOCKMODE  lockmode 
)
static

Definition at line 6671 of file tablecmds.c.

6672 {
6673  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6674  {
6675  List *inh;
6676  ListCell *cell;
6677 
6678  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6679  /* first element is the parent rel; must ignore it */
6680  for_each_from(cell, inh, 1)
6681  {
6682  Relation childrel;
6683 
6684  /* find_all_inheritors already got lock */
6685  childrel = table_open(lfirst_oid(cell), NoLock);
6686  CheckAlterTableIsSafe(childrel);
6687  table_close(childrel, NoLock);
6688  }
6689  list_free(inh);
6690  }
6691 }
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 12959 of file tablecmds.c.

12960 {
12961  Assert(expr != NULL);
12962 
12963  for (;;)
12964  {
12965  /* only one varno, so no need to check that */
12966  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
12967  return false;
12968  else if (IsA(expr, RelabelType))
12969  expr = (Node *) ((RelabelType *) expr)->arg;
12970  else if (IsA(expr, CoerceToDomain))
12971  {
12972  CoerceToDomain *d = (CoerceToDomain *) expr;
12973 
12975  return true;
12976  expr = (Node *) d->arg;
12977  }
12978  else if (IsA(expr, FuncExpr))
12979  {
12980  FuncExpr *f = (FuncExpr *) expr;
12981 
12982  switch (f->funcid)
12983  {
12984  case F_TIMESTAMPTZ_TIMESTAMP:
12985  case F_TIMESTAMP_TIMESTAMPTZ:
12987  return true;
12988  else
12989  expr = linitial(f->args);
12990  break;
12991  default:
12992  return true;
12993  }
12994  }
12995  else
12996  return true;
12997  }
12998 }
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:6273
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:1400

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

4725 {
4726  List *wqueue = NIL;
4727  ListCell *lcmd;
4728 
4729  /* Phase 1: preliminary examination of commands, create work queue */
4730  foreach(lcmd, cmds)
4731  {
4732  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4733 
4734  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4735  }
4736 
4737  /* Close the relation, but keep lock until commit */
4738  relation_close(rel, NoLock);
4739 
4740  /* Phase 2: update system catalogs */
4741  ATRewriteCatalogs(&wqueue, lockmode, context);
4742 
4743  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4744  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4745 }
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5146
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4757
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5706

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

19932 {
19933  List *constraints;
19934  ListCell *cell;
19935 
19936  constraints = GetParentedForeignKeyRefs(partition);
19937 
19938  foreach(cell, constraints)
19939  {
19940  Oid constrOid = lfirst_oid(cell);
19941  HeapTuple tuple;
19942  Form_pg_constraint constrForm;
19943  Relation rel;
19944  Trigger trig = {0};
19945 
19946  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
19947  if (!HeapTupleIsValid(tuple))
19948  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
19949  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
19950 
19951  Assert(OidIsValid(constrForm->conparentid));
19952  Assert(constrForm->confrelid == RelationGetRelid(partition));
19953 
19954  /* prevent data changes into the referencing table until commit */
19955  rel = table_open(constrForm->conrelid, ShareLock);
19956 
19957  trig.tgoid = InvalidOid;
19958  trig.tgname = NameStr(constrForm->conname);
19960  trig.tgisinternal = true;
19961  trig.tgconstrrelid = RelationGetRelid(partition);
19962  trig.tgconstrindid = constrForm->conindid;
19963  trig.tgconstraint = constrForm->oid;
19964  trig.tgdeferrable = false;
19965  trig.tginitdeferred = false;
19966  /* we needn't fill in remaining fields */
19967 
19968  RI_PartitionRemove_Check(&trig, rel, partition);
19969 
19970  ReleaseSysCache(tuple);
19971 
19972  table_close(rel, NoLock);
19973  }
19974 }
#define ShareLock
Definition: lockdefs.h:40
FormData_pg_constraint * Form_pg_constraint
void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1654
char tgenabled
Definition: reltrigger.h:30
Oid tgoid
Definition: reltrigger.h:25
Oid tgconstrindid
Definition: reltrigger.h:34
Oid tgconstraint
Definition: reltrigger.h:35
Oid tgconstrrelid
Definition: reltrigger.h:33
char * tgname
Definition: reltrigger.h:27
bool tgdeferrable
Definition: reltrigger.h:36
bool tginitdeferred
Definition: reltrigger.h:37
bool tgisinternal
Definition: reltrigger.h:31
static List * GetParentedForeignKeyRefs(Relation partition)
Definition: tablecmds.c:19878
#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 17549 of file tablecmds.c.

17551 {
17552  ListCell *cur_item;
17553 
17554  foreach(cur_item, on_commits)
17555  {
17556  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
17557 
17558  if (!isCommit && oc->creating_subid == mySubid)
17559  {
17560  /* cur_item must be removed */
17562  pfree(oc);
17563  }
17564  else
17565  {
17566  /* cur_item must be preserved */
17567  if (oc->creating_subid == mySubid)
17568  oc->creating_subid = parentSubid;
17569  if (oc->deleting_subid == mySubid)
17570  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
17571  }
17572  }
17573 }
#define InvalidSubTransactionId
Definition: c.h:658
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
SubTransactionId creating_subid
Definition: tablecmds.c:125
SubTransactionId deleting_subid
Definition: tablecmds.c:126
static List * on_commits
Definition: tablecmds.c:129

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 17517 of file tablecmds.c.

17518 {
17519  ListCell *cur_item;
17520 
17521  foreach(cur_item, on_commits)
17522  {
17523  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
17524 
17525  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
17527  {
17528  /* cur_item must be removed */
17530  pfree(oc);
17531  }
17532  else
17533  {
17534  /* cur_item must be preserved */
17537  }
17538  }
17539 }

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

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

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

Referenced by ATExecCmd().

◆ ATExecAddConstraint()

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

Definition at line 9330 of file tablecmds.c.

9333 {
9335 
9336  Assert(IsA(newConstraint, Constraint));
9337 
9338  /*
9339  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
9340  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
9341  * switch anyway to make it easier to add more code later.
9342  */
9343  switch (newConstraint->contype)
9344  {
9345  case CONSTR_CHECK:
9346  address =
9347  ATAddCheckConstraint(wqueue, tab, rel,
9348  newConstraint, recurse, false, is_readd,
9349  lockmode);
9350  break;
9351 
9352  case CONSTR_FOREIGN:
9353 
9354  /*
9355  * Assign or validate constraint name
9356  */
9357  if (newConstraint->conname)
9358  {
9360  RelationGetRelid(rel),
9361  newConstraint->conname))
9362  ereport(ERROR,
9364  errmsg("constraint \"%s\" for relation \"%s\" already exists",
9365  newConstraint->conname,
9366  RelationGetRelationName(rel))));
9367  }
9368  else
9369  newConstraint->conname =
9372  "fkey",
9373  RelationGetNamespace(rel),
9374  NIL);
9375 
9376  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
9377  newConstraint,
9378  recurse, false,
9379  lockmode);
9380  break;
9381 
9382  default:
9383  elog(ERROR, "unrecognized constraint type: %d",
9384  (int) newConstraint->contype);
9385  }
9386 
9387  return address;
9388 }
@ CONSTR_CHECK
Definition: parsenodes.h:2710
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:9582

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

Referenced by ATExecCmd().

◆ ATExecAddIdentity()

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

Definition at line 7998 of file tablecmds.c.

8000 {
8001  Relation attrelation;
8002  HeapTuple tuple;
8003  Form_pg_attribute attTup;
8005  ObjectAddress address;
8006  ColumnDef *cdef = castNode(ColumnDef, def);
8007  bool ispartitioned;
8008 
8009  ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
8010  if (ispartitioned && !recurse)
8011  ereport(ERROR,
8012  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8013  errmsg("cannot add identity to a column of only the partitioned table"),
8014  errhint("Do not specify the ONLY keyword.")));
8015 
8016  if (rel->rd_rel->relispartition && !recursing)
8017  ereport(ERROR,
8018  errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8019  errmsg("cannot add identity to a column of a partition"));
8020 
8021  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
8022 
8023  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8024  if (!HeapTupleIsValid(tuple))
8025  ereport(ERROR,
8026  (errcode(ERRCODE_UNDEFINED_COLUMN),
8027  errmsg("column \"%s\" of relation \"%s\" does not exist",
8028  colName, RelationGetRelationName(rel))));
8029  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
8030  attnum = attTup->attnum;
8031 
8032  /* Can't alter a system attribute */
8033  if (attnum <= 0)
8034  ereport(ERROR,
8035  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8036  errmsg("cannot alter system column \"%s\"",
8037  colName)));
8038 
8039  /*
8040  * Creating a column as identity implies NOT NULL, so adding the identity
8041  * to an existing column that is not NOT NULL would create a state that
8042  * cannot be reproduced without contortions.
8043  */
8044  if (!attTup->attnotnull)
8045  ereport(ERROR,
8046  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8047  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
8048  colName, RelationGetRelationName(rel))));
8049 
8050  if (attTup->attidentity)
8051  ereport(ERROR,
8052  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8053  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
8054  colName, RelationGetRelationName(rel))));
8055 
8056  if (attTup->atthasdef)
8057  ereport(ERROR,
8058  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8059  errmsg("column \"%s\" of relation \"%s\" already has a default value",
8060  colName, RelationGetRelationName(rel))));
8061 
8062  attTup->attidentity = cdef->identity;
8063  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
8064 
8065  InvokeObjectPostAlterHook(RelationRelationId,
8066  RelationGetRelid(rel),
8067  attTup->attnum);
8068  ObjectAddressSubSet(address, RelationRelationId,
8069  RelationGetRelid(rel), attnum);
8070  heap_freetuple(tuple);
8071 
8072  table_close(attrelation, RowExclusiveLock);
8073 
8074  /*
8075  * Recurse to propagate the identity column to partitions. Identity is
8076  * not inherited in regular inheritance children.
8077  */
8078  if (recurse && ispartitioned)
8079  {
8080  List *children;
8081  ListCell *lc;
8082 
8083  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8084 
8085  foreach(lc, children)
8086  {
8087  Relation childrel;
8088 
8089  childrel = table_open(lfirst_oid(lc), NoLock);
8090  ATExecAddIdentity(childrel, colName, def, lockmode, recurse, true);
8091  table_close(childrel, NoLock);
8092  }
8093  }
8094 
8095  return address;
8096 }
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:7998

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

9156 {
9157  bool check_rights;
9158  bool skip_build;
9159  bool quiet;
9160  ObjectAddress address;
9161 
9162  Assert(IsA(stmt, IndexStmt));
9163  Assert(!stmt->concurrent);
9164 
9165  /* The IndexStmt has already been through transformIndexStmt */
9166  Assert(stmt->transformed);
9167 
9168  /* suppress schema rights check when rebuilding existing index */
9169  check_rights = !is_rebuild;
9170  /* skip index build if phase 3 will do it or we're reusing an old one */
9171  skip_build = tab->rewrite > 0 || RelFileNumberIsValid(stmt->oldNumber);
9172  /* suppress notices when rebuilding existing index */
9173  quiet = is_rebuild;
9174 
9175  address = DefineIndex(RelationGetRelid(rel),
9176  stmt,
9177  InvalidOid, /* no predefined OID */
9178  InvalidOid, /* no parent index */
9179  InvalidOid, /* no parent constraint */
9180  -1, /* total_parts unknown */
9181  true, /* is_alter_table */
9182  check_rights,
9183  false, /* check_not_in_use - we did it already */
9184  skip_build,
9185  quiet);
9186 
9187  /*
9188  * If TryReuseIndex() stashed a relfilenumber for us, we used it for the
9189  * new index instead of building from scratch. Restore associated fields.
9190  * This may store InvalidSubTransactionId in both fields, in which case
9191  * relcache.c will assume it can rebuild the relcache entry. Hence, do
9192  * this after the CCI that made catalog rows visible to any rebuild. The
9193  * DROP of the old edition of this index will have scheduled the storage
9194  * for deletion at commit, so cancel that pending deletion.
9195  */
9196  if (RelFileNumberIsValid(stmt->oldNumber))
9197  {
9198  Relation irel = index_open(address.objectId, NoLock);
9199 
9200  irel->rd_createSubid = stmt->oldCreateSubid;
9201  irel->rd_firstRelfilelocatorSubid = stmt->oldFirstRelfilelocatorSubid;
9202  RelationPreserveStorage(irel->rd_locator, true);
9203  index_close(irel, NoLock);
9204  }
9205 
9206  return address;
9207 }
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
ObjectAddress DefineIndex(Oid tableId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, int total_parts, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition: indexcmds.c:531
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
void RelationPreserveStorage(RelFileLocator rlocator, bool atCommit)
Definition: storage.c:251
SubTransactionId rd_firstRelfilelocatorSubid
Definition: rel.h:106
SubTransactionId rd_createSubid
Definition: rel.h:103
RelFileLocator rd_locator
Definition: rel.h:57

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

Referenced by ATExecCmd().

◆ ATExecAddIndexConstraint()

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

Definition at line 9238 of file tablecmds.c.

9240 {
9241  Oid index_oid = stmt->indexOid;
9242  Relation indexRel;
9243  char *indexName;
9244  IndexInfo *indexInfo;
9245  char *constraintName;
9246  char constraintType;
9247  ObjectAddress address;
9248  bits16 flags;
9249 
9250  Assert(IsA(stmt, IndexStmt));
9251  Assert(OidIsValid(index_oid));
9252  Assert(stmt->isconstraint);
9253 
9254  /*
9255  * Doing this on partitioned tables is not a simple feature to implement,
9256  * so let's punt for now.
9257  */
9258  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9259  ereport(ERROR,
9260  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9261  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
9262 
9263  indexRel = index_open(index_oid, AccessShareLock);
9264 
9265  indexName = pstrdup(RelationGetRelationName(indexRel));
9266 
9267  indexInfo = BuildIndexInfo(indexRel);
9268 
9269  /* this should have been checked at parse time */
9270  if (!indexInfo->ii_Unique)
9271  elog(ERROR, "index \"%s\" is not unique", indexName);
9272 
9273  /*
9274  * Determine name to assign to constraint. We require a constraint to
9275  * have the same name as the underlying index; therefore, use the index's
9276  * existing name as the default constraint name, and if the user
9277  * explicitly gives some other name for the constraint, rename the index
9278  * to match.
9279  */
9280  constraintName = stmt->idxname;
9281  if (constraintName == NULL)
9282  constraintName = indexName;
9283  else if (strcmp(constraintName, indexName) != 0)
9284  {
9285  ereport(NOTICE,
9286  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
9287  indexName, constraintName)));
9288  RenameRelationInternal(index_oid, constraintName, false, true);
9289  }
9290 
9291  /* Extra checks needed if making primary key */
9292  if (stmt->primary)
9293  index_check_primary_key(rel, indexInfo, true, stmt);
9294 
9295  /* Note we currently don't support EXCLUSION constraints here */
9296  if (stmt->primary)
9297  constraintType = CONSTRAINT_PRIMARY;
9298  else
9299  constraintType = CONSTRAINT_UNIQUE;
9300 
9301  /* Create the catalog entries for the constraint */
9304  (stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
9305  (stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
9306  (stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
9307 
9308  address = index_constraint_create(rel,
9309  index_oid,
9310  InvalidOid,
9311  indexInfo,
9312  constraintName,
9313  constraintType,
9314  flags,
9316  false); /* is_internal */
9317 
9318  index_close(indexRel, NoLock);
9319 
9320  return address;
9321 }
uint16 bits16
Definition: c.h:514
void index_check_primary_key(Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
Definition: index.c:201
ObjectAddress index_constraint_create(Relation heapRelation, Oid indexRelationId, Oid parentConstraintId, const IndexInfo *indexInfo, const char *constraintName, char constraintType, bits16 constr_flags, bool allow_system_table_mods, bool is_internal)
Definition: index.c:1880
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2403
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:94
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:95
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:92
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition: index.h:91
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:93
char * pstrdup(const char *in)
Definition: mcxt.c:1695
bool ii_Unique
Definition: execnodes.h:197
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:4108

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

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

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

Referenced by ATExecCmd().

◆ ATExecAddOf()

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

Definition at line 16322 of file tablecmds.c.

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

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

Referenced by ATExecCmd().

◆ ATExecAddStatistics()