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 "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_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_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "catalog/toasting.h"
#include "commands/cluster.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/policy.h"
#include "commands/sequence.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
#include "commands/user.h"
#include "executor/executor.h"
#include "foreign/fdwapi.h"
#include "foreign/foreign.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/parsenodes.h"
#include "optimizer/optimizer.h"
#include "parser/parse_clause.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "parser/parse_utilcmd.h"
#include "parser/parser.h"
#include "partitioning/partbounds.h"
#include "partitioning/partdesc.h"
#include "pgstat.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteHandler.h"
#include "rewrite/rewriteManip.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "storage/lock.h"
#include "storage/predicate.h"
#include "storage/smgr.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/partcache.h"
#include "utils/pg_locale.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 dependency graph for tablecmds.c:

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Functions

static void truncate_check_rel (Oid relid, Form_pg_class reltuple)
 
static void truncate_check_perms (Oid relid, Form_pg_class reltuple)
 
static void truncate_check_activity (Relation rel)
 
static void truncate_update_partedrel_stats (List *parted_rels)
 
static void RangeVarCallbackForTruncate (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
static ListMergeAttributes (List *schema, List *supers, char relpersistence, bool is_partition, List **supconstr)
 
static bool MergeCheckConstraint (List *constraints, char *name, Node *expr)
 
static void MergeAttributesIntoExisting (Relation child_rel, Relation parent_rel)
 
static void MergeConstraintsIntoExisting (Relation child_rel, Relation parent_rel)
 
static void StoreCatalogInheritance (Oid relationId, List *supers, bool child_is_partition)
 
static void StoreCatalogInheritance1 (Oid relationId, Oid parentOid, int32 seqNumber, Relation inhRelation, bool child_is_partition)
 
static int findAttrByName (const char *attributeName, List *schema)
 
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 ObjectAddress ATExecValidateConstraint (List **wqueue, Relation rel, char *constrName, bool recurse, bool recursing, LOCKMODE lockmode)
 
static int transformColumnNameList (Oid relId, List *colList, int16 *attnums, Oid *atttypids)
 
static int transformFkeyGetPrimaryKey (Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
 
static Oid transformFkeyCheckAttrs (Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
 
static void checkFkeyPermissions (Relation rel, int16 *attnums, int natts)
 
static CoercionPathType findFkeyCast (Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
 
static void validateForeignKeyConstraint (char *conname, Relation rel, Relation pkrel, Oid pkindOid, Oid constraintOid)
 
static void ATController (AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATPrepCmd (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATRewriteCatalogs (List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATExecCmd (List **wqueue, AlteredTableInfo *tab, AlterTableCmd *cmd, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
 
static AlterTableCmdATParseTransformCmd (List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
 
static void ATRewriteTables (AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATRewriteTable (AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 
static AlteredTableInfoATGetQueueEntry (List **wqueue, Relation rel)
 
static void ATSimplePermissions (Relation rel, int allowed_targets)
 
static void ATWrongRelkindError (Relation rel, int allowed_targets)
 
static void ATSimpleRecursion (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATCheckPartitionsNotInUse (Relation rel, LOCKMODE lockmode)
 
static void ATTypedTableRecursion (List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static Listfind_typed_table_dependencies (Oid typeOid, const char *typeName, DropBehavior behavior)
 
static void ATPrepAddColumn (List **wqueue, Relation rel, bool recurse, bool recursing, bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static ObjectAddress ATExecAddColumn (List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd **cmd, bool recurse, bool recursing, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
 
static bool check_for_column_name_collision (Relation rel, const char *colname, bool if_not_exists)
 
static void add_column_datatype_dependency (Oid relid, int32 attnum, Oid typid)
 
static void add_column_collation_dependency (Oid relid, int32 attnum, Oid collid)
 
static 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)
 
static ObjectAddress ATExecSetIdentity (Relation rel, const char *colName, Node *def, LOCKMODE lockmode)
 
static ObjectAddress ATExecDropIdentity (Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
 
static void ATPrepDropExpression (Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
 
static ObjectAddress ATExecDropExpression (Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetStatistics (Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetOptions (Relation rel, const char *colName, Node *options, bool isReset, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetStorage (Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
 
static void ATPrepDropColumn (List **wqueue, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static ObjectAddress ATExecDropColumn (List **wqueue, Relation rel, const char *colName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode, ObjectAddresses *addrs)
 
static 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, Oid parentConstr, 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, bool old_check_ok)
 
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, bool old_check_ok, LOCKMODE lockmode)
 
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)
 
static void createForeignKeyActionTriggers (Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
 
static bool tryAttachPartitionForeignKey (ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop)
 
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 RememberConstraintForRebuilding (Oid conoid, AlteredTableInfo *tab)
 
static void RememberIndexForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
static void RememberStatisticsForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
static void ATPostAlterTypeCleanup (List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
 
static void ATPostAlterTypeParse (Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, List **wqueue, LOCKMODE lockmode, bool rewrite)
 
static void RebuildConstraintComment (AlteredTableInfo *tab, int pass, Oid objid, Relation rel, List *domname, const char *conname)
 
static void TryReuseIndex (Oid oldId, IndexStmt *stmt)
 
static void TryReuseForeignKey (Oid oldId, Constraint *con)
 
static ObjectAddress ATExecAlterColumnGenericOptions (Relation rel, const char *colName, List *options, LOCKMODE lockmode)
 
static void change_owner_fix_column_acls (Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
 
static void change_owner_recurse_to_sequences (Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
 
static ObjectAddress ATExecClusterOn (Relation rel, const char *indexName, LOCKMODE lockmode)
 
static void ATExecDropCluster (Relation rel, LOCKMODE lockmode)
 
static 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, 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 (AlteredTableInfo *tab, Relation rel, const char *column, Node *newValue, LOCKMODE lockmode)
 
static void index_copy_data (Relation rel, RelFileNode newrnode)
 
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, char *strategy)
 
static void ComputePartitionAttrs (ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, char strategy)
 
static void CreateInheritance (Relation child_rel, Relation parent_rel)
 
static void RemoveInheritance (Relation child_rel, Relation parent_rel, bool allow_detached)
 
static ObjectAddress ATExecAttachPartition (List **wqueue, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
 
static void AttachPartitionEnsureIndexes (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 rel, 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 void ATExecAlterCollationRefreshVersion (Relation rel, List *coll)
 
static char GetAttributeCompression (Form_pg_attribute att, char *compression)
 
ObjectAddress DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
 
static void DropErrorMsgNonExistent (RangeVar *rel, char rightkind, bool missing_ok)
 
static void DropErrorMsgWrongType (const char *relname, char wrongkind, char rightkind)
 
void RemoveRelations (DropStmt *drop)
 
void ExecuteTruncate (TruncateStmt *stmt)
 
void ExecuteTruncateGuts (List *explicit_rels, List *relids, List *relids_extra, List *relids_logged, DropBehavior behavior, bool restart_seqs)
 
void SetRelationHasSubclass (Oid relationId, bool relhassubclass)
 
bool CheckRelationTableSpaceMove (Relation rel, Oid newTableSpaceId)
 
void SetRelationTableSpace (Relation rel, Oid newTableSpaceId, Oid newRelFileNode)
 
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 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)
 
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, char newcompression, char newstorage, LOCKMODE lockmode)
 
static void CreateFKCheckTrigger (Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, bool on_insert)
 
static void RememberReplicaIdentityForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
static void RememberClusterOnForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
void ATExecChangeOwner (Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
 
Oid AlterTableMoveAll (AlterTableMoveAllStmt *stmt)
 
static char * decompile_conbin (HeapTuple contup, TupleDesc tupdesc)
 
static bool constraints_equivalent (HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
 
static void MarkInheritDetached (Relation child_rel, Relation parent_rel)
 
static void relation_mark_replica_identity (Relation rel, char ri_type, Oid indexOid, bool is_internal)
 
ObjectAddress AlterTableNamespace (AlterObjectSchemaStmt *stmt, Oid *oldschema)
 
void AlterTableNamespaceInternal (Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
 
void AlterRelationNamespaceInternal (Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
 
void register_on_commit_action (Oid relid, OnCommitAction action)
 
void remove_on_commit_action (Oid relid)
 
void PreCommit_on_commit_actions (void)
 
void AtEOXact_on_commit_actions (bool isCommit)
 
void AtEOSubXact_on_commit_actions (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
void RangeVarCallbackOwnsTable (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
void RangeVarCallbackOwnsRelation (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
bool PartConstraintImpliedByRelConstraint (Relation scanrel, List *partConstraint)
 
static void RangeVarCallbackForAttachIndex (const RangeVar *rv, Oid relOid, Oid oldRelOid, void *arg)
 

Variables

static Liston_commits = NIL
 
static const struct dropmsgstrings dropmsgstringarray []
 

Macro Definition Documentation

◆ AT_NUM_PASSES

#define AT_NUM_PASSES   11

Definition at line 154 of file tablecmds.c.

Referenced by ATRewriteCatalogs().

◆ AT_PASS_ADD_COL

#define AT_PASS_ADD_COL   4 /* ADD COLUMN */

Definition at line 147 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_ADD_CONSTR

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

Definition at line 148 of file tablecmds.c.

Referenced by ATExecCmd(), and ATPrepCmd().

◆ AT_PASS_ADD_INDEX

#define AT_PASS_ADD_INDEX   8 /* ADD indexes */

Definition at line 151 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_ADD_INDEXCONSTR

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

Definition at line 150 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_ADD_OTHERCONSTR

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

Definition at line 152 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_ALTER_TYPE

#define AT_PASS_ALTER_TYPE   1 /* ALTER COLUMN TYPE */

Definition at line 143 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATRewriteCatalogs().

◆ AT_PASS_COL_ATTRS

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

Definition at line 149 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_DROP

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

Definition at line 142 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_MISC

#define AT_PASS_MISC   10 /* other stuff */

Definition at line 153 of file tablecmds.c.

Referenced by ATParseTransformCmd(), ATPostAlterTypeParse(), and ATPrepCmd().

◆ AT_PASS_OLD_CONSTR

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

Definition at line 145 of file tablecmds.c.

Referenced by ATPostAlterTypeCleanup(), and ATPostAlterTypeParse().

◆ AT_PASS_OLD_INDEX

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

Definition at line 144 of file tablecmds.c.

Referenced by ATPostAlterTypeParse().

◆ AT_PASS_UNSET

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

Definition at line 141 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ ATT_COMPOSITE_TYPE

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 310 of file tablecmds.c.

Referenced by ATPrepCmd(), ATSimplePermissions(), and ATWrongRelkindError().

◆ ATT_FOREIGN_TABLE

◆ ATT_INDEX

#define ATT_INDEX   0x0008

Definition at line 309 of file tablecmds.c.

Referenced by ATPrepCmd(), ATSimplePermissions(), and ATWrongRelkindError().

◆ ATT_MATVIEW

#define ATT_MATVIEW   0x0004

Definition at line 308 of file tablecmds.c.

Referenced by ATPrepCmd(), ATSimplePermissions(), and ATWrongRelkindError().

◆ ATT_PARTITIONED_INDEX

#define ATT_PARTITIONED_INDEX   0x0040

Definition at line 312 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATSimplePermissions().

◆ ATT_TABLE

◆ ATT_VIEW

#define ATT_VIEW   0x0002

Definition at line 307 of file tablecmds.c.

Referenced by ATPrepCmd(), ATSimplePermissions(), and ATWrongRelkindError().

◆ child_dependency_type

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

Definition at line 334 of file tablecmds.c.

Referenced by RemoveInheritance(), and StoreCatalogInheritance1().

Typedef Documentation

◆ AlteredTableInfo

◆ ForeignTruncateInfo

◆ NewColumnValue

◆ NewConstraint

typedef struct NewConstraint NewConstraint

◆ OnCommitItem

typedef struct OnCommitItem OnCommitItem

Function Documentation

◆ add_column_collation_dependency()

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

Definition at line 6952 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

6953 {
6954  ObjectAddress myself,
6955  referenced;
6956 
6957  /* We know the default collation is pinned, so don't bother recording it */
6958  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
6959  {
6960  myself.classId = RelationRelationId;
6961  myself.objectId = relid;
6962  myself.objectSubId = attnum;
6963  referenced.classId = CollationRelationId;
6964  referenced.objectId = collid;
6965  referenced.objectSubId = 0;
6966  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
6967  }
6968 }
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
#define OidIsValid(objectId)
Definition: c.h:710
int16 attnum
Definition: pg_attribute.h:83

◆ add_column_datatype_dependency()

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

Definition at line 6934 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

6935 {
6936  ObjectAddress myself,
6937  referenced;
6938 
6939  myself.classId = RelationRelationId;
6940  myself.objectId = relid;
6941  myself.objectSubId = attnum;
6942  referenced.classId = TypeRelationId;
6943  referenced.objectId = typid;
6944  referenced.objectSubId = 0;
6945  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
6946 }
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
int16 attnum
Definition: pg_attribute.h:83

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

Definition at line 9278 of file tablecmds.c.

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

9283 {
9284  ObjectAddress address;
9285  Oid constrOid;
9286  char *conname;
9287  bool conislocal;
9288  int coninhcount;
9289  bool connoinherit;
9290 
9291  /*
9292  * Verify relkind for each referenced partition. At the top level, this
9293  * is redundant with a previous check, but we need it when recursing.
9294  */
9295  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9296  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9297  ereport(ERROR,
9298  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9299  errmsg("referenced relation \"%s\" is not a table",
9300  RelationGetRelationName(pkrel))));
9301 
9302  /*
9303  * Caller supplies us with a constraint name; however, it may be used in
9304  * this partition, so come up with a different one in that case.
9305  */
9307  RelationGetRelid(rel),
9308  fkconstraint->conname))
9311  "fkey",
9312  RelationGetNamespace(rel), NIL);
9313  else
9314  conname = fkconstraint->conname;
9315 
9316  if (OidIsValid(parentConstr))
9317  {
9318  conislocal = false;
9319  coninhcount = 1;
9320  connoinherit = false;
9321  }
9322  else
9323  {
9324  conislocal = true;
9325  coninhcount = 0;
9326 
9327  /*
9328  * always inherit for partitioned tables, never for legacy inheritance
9329  */
9330  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
9331  }
9332 
9333  /*
9334  * Record the FK constraint in pg_constraint.
9335  */
9336  constrOid = CreateConstraintEntry(conname,
9337  RelationGetNamespace(rel),
9338  CONSTRAINT_FOREIGN,
9339  fkconstraint->deferrable,
9340  fkconstraint->initdeferred,
9341  fkconstraint->initially_valid,
9342  parentConstr,
9343  RelationGetRelid(rel),
9344  fkattnum,
9345  numfks,
9346  numfks,
9347  InvalidOid, /* not a domain constraint */
9348  indexOid,
9349  RelationGetRelid(pkrel),
9350  pkattnum,
9351  pfeqoperators,
9352  ppeqoperators,
9353  ffeqoperators,
9354  numfks,
9355  fkconstraint->fk_upd_action,
9356  fkconstraint->fk_del_action,
9357  fkconstraint->fk_matchtype,
9358  NULL, /* no exclusion constraint */
9359  NULL, /* no check constraint */
9360  NULL,
9361  conislocal, /* islocal */
9362  coninhcount, /* inhcount */
9363  connoinherit, /* conNoInherit */
9364  false); /* is_internal */
9365 
9366  ObjectAddressSet(address, ConstraintRelationId, constrOid);
9367 
9368  /*
9369  * Mark the child constraint as part of the parent constraint; it must not
9370  * be dropped on its own. (This constraint is deleted when the partition
9371  * is detached, but a special check needs to occur that the partition
9372  * contains no referenced values.)
9373  */
9374  if (OidIsValid(parentConstr))
9375  {
9376  ObjectAddress referenced;
9377 
9378  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9379  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
9380  }
9381 
9382  /* make new constraint visible, in case we add more */
9384 
9385  /*
9386  * If the referenced table is a plain relation, create the action triggers
9387  * that enforce the constraint.
9388  */
9389  if (pkrel->rd_rel->relkind == RELKIND_RELATION)
9390  {
9392  fkconstraint,
9393  constrOid, indexOid);
9394  }
9395 
9396  /*
9397  * If the referenced table is partitioned, recurse on ourselves to handle
9398  * each partition. We need one pg_constraint row created for each
9399  * partition in addition to the pg_constraint row for the parent table.
9400  */
9401  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9402  {
9403  PartitionDesc pd = RelationGetPartitionDesc(pkrel, false);
9404 
9405  for (int i = 0; i < pd->nparts; i++)
9406  {
9407  Relation partRel;
9408  AttrMap *map;
9409  AttrNumber *mapped_pkattnum;
9410  Oid partIndexId;
9411 
9412  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
9413 
9414  /*
9415  * Map the attribute numbers in the referenced side of the FK
9416  * definition to match the partition's column layout.
9417  */
9419  RelationGetDescr(pkrel));
9420  if (map)
9421  {
9422  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
9423  for (int j = 0; j < numfks; j++)
9424  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
9425  }
9426  else
9427  mapped_pkattnum = pkattnum;
9428 
9429  /* do the deed */
9430  partIndexId = index_get_partition(partRel, indexOid);
9431  if (!OidIsValid(partIndexId))
9432  elog(ERROR, "index for %u not found in partition %s",
9433  indexOid, RelationGetRelationName(partRel));
9434  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
9435  partIndexId, constrOid, numfks,
9436  mapped_pkattnum, fkattnum,
9437  pfeqoperators, ppeqoperators, ffeqoperators,
9438  old_check_ok);
9439 
9440  /* Done -- clean up (but keep the lock) */
9441  table_close(partRel, NoLock);
9442  if (map)
9443  {
9444  pfree(mapped_pkattnum);
9445  free_attrmap(map);
9446  }
9447  }
9448  }
9449 
9450  return address;
9451 }
#define NIL
Definition: pg_list.h:65
Oid index_get_partition(Relation partition, Oid indexId)
Definition: partition.c:175
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8660
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void free_attrmap(AttrMap *map)
Definition: attmap.c:57
#define RelationGetDescr(relation)
Definition: rel.h:483
char fk_matchtype
Definition: parsenodes.h:2267
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, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:50
int errcode(int sqlerrcode)
Definition: elog.c:698
bool initdeferred
Definition: parsenodes.h:2235
PartitionDesc RelationGetPartitionDesc(Relation rel, bool include_detached)
Definition: partdesc.c:65
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
char * conname
Definition: parsenodes.h:2233
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
Definition: attmap.h:34
void pfree(void *pointer)
Definition: mcxt.c:1169
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, bool old_check_ok)
Definition: tablecmds.c:9278
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:259
#define ERROR
Definition: elog.h:46
bool deferrable
Definition: parsenodes.h:2234
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:491
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:11057
void CommandCounterIncrement(void)
Definition: xact.c:1021
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2276
#define ereport(elevel,...)
Definition: elog.h:157
char fk_del_action
Definition: parsenodes.h:2269
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
AttrNumber * attnums
Definition: attmap.h:36
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
int i
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:457
List * fk_attrs
Definition: parsenodes.h:2265
char fk_upd_action
Definition: parsenodes.h:2268
#define RelationGetNamespace(relation)
Definition: rel.h:498

◆ 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,
bool  old_check_ok,
LOCKMODE  lockmode 
)
static

Definition at line 9483 of file tablecmds.c.

References AssertArg, ATGetQueueEntry(), AttrMap::attnums, build_attrmap_by_name(), CheckTableNotInUse(), ChooseConstraintName(), ChooseForeignKeyConstraintNameAddition(), CommandCounterIncrement(), NewConstraint::conid, Constraint::conname, CONSTR_FOREIGN, CONSTRAINT_RELATION, ConstraintNameIsUsed(), AlteredTableInfo::constraints, NewConstraint::contype, copyObject, CreateConstraintEntry(), createForeignKeyCheckTriggers(), Constraint::deferrable, DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, ereport, errcode(), errmsg(), ERROR, Constraint::fk_attrs, Constraint::fk_del_action, Constraint::fk_matchtype, Constraint::fk_upd_action, get_constraint_name(), i, INDEX_MAX_KEYS, Constraint::initdeferred, Constraint::initially_valid, InvalidOid, 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, Constraint::skip_validation, table_close(), table_open(), and tryAttachPartitionForeignKey().

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferencing().

9488 {
9489  AssertArg(OidIsValid(parentConstr));
9490 
9491  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
9492  ereport(ERROR,
9493  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9494  errmsg("foreign key constraints are not supported on foreign tables")));
9495 
9496  /*
9497  * If the referencing relation is a plain table, add the check triggers to
9498  * it and, if necessary, schedule it to be checked in Phase 3.
9499  *
9500  * If the relation is partitioned, drill down to do it to its partitions.
9501  */
9502  if (rel->rd_rel->relkind == RELKIND_RELATION)
9503  {
9505  RelationGetRelid(pkrel),
9506  fkconstraint,
9507  parentConstr,
9508  indexOid);
9509 
9510  /*
9511  * Tell Phase 3 to check that the constraint is satisfied by existing
9512  * rows. We can skip this during table creation, when requested
9513  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
9514  * and when we're recreating a constraint following a SET DATA TYPE
9515  * operation that did not impugn its validity.
9516  */
9517  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
9518  {
9519  NewConstraint *newcon;
9520  AlteredTableInfo *tab;
9521 
9522  tab = ATGetQueueEntry(wqueue, rel);
9523 
9524  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9525  newcon->name = get_constraint_name(parentConstr);
9526  newcon->contype = CONSTR_FOREIGN;
9527  newcon->refrelid = RelationGetRelid(pkrel);
9528  newcon->refindid = indexOid;
9529  newcon->conid = parentConstr;
9530  newcon->qual = (Node *) fkconstraint;
9531 
9532  tab->constraints = lappend(tab->constraints, newcon);
9533  }
9534  }
9535  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9536  {
9537  PartitionDesc pd = RelationGetPartitionDesc(rel, false);
9538 
9539  /*
9540  * Recurse to take appropriate action on each partition; either we
9541  * find an existing constraint to reparent to ours, or we create a new
9542  * one.
9543  */
9544  for (int i = 0; i < pd->nparts; i++)
9545  {
9546  Oid partitionId = pd->oids[i];
9547  Relation partition = table_open(partitionId, lockmode);
9548  List *partFKs;
9549  AttrMap *attmap;
9550  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
9551  bool attached;
9552  char *conname;
9553  Oid constrOid;
9554  ObjectAddress address,
9555  referenced;
9556  ListCell *cell;
9557 
9558  CheckTableNotInUse(partition, "ALTER TABLE");
9559 
9560  attmap = build_attrmap_by_name(RelationGetDescr(partition),
9561  RelationGetDescr(rel));
9562  for (int j = 0; j < numfks; j++)
9563  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
9564 
9565  /* Check whether an existing constraint can be repurposed */
9566  partFKs = copyObject(RelationGetFKeyList(partition));
9567  attached = false;
9568  foreach(cell, partFKs)
9569  {
9570  ForeignKeyCacheInfo *fk;
9571 
9572  fk = lfirst_node(ForeignKeyCacheInfo, cell);
9574  partitionId,
9575  parentConstr,
9576  numfks,
9577  mapped_fkattnum,
9578  pkattnum,
9579  pfeqoperators))
9580  {
9581  attached = true;
9582  break;
9583  }
9584  }
9585  if (attached)
9586  {
9587  table_close(partition, NoLock);
9588  continue;
9589  }
9590 
9591  /*
9592  * No luck finding a good constraint to reuse; create our own.
9593  */
9595  RelationGetRelid(partition),
9596  fkconstraint->conname))
9597  conname = ChooseConstraintName(RelationGetRelationName(partition),
9599  "fkey",
9600  RelationGetNamespace(partition), NIL);
9601  else
9602  conname = fkconstraint->conname;
9603  constrOid =
9604  CreateConstraintEntry(conname,
9605  RelationGetNamespace(partition),
9606  CONSTRAINT_FOREIGN,
9607  fkconstraint->deferrable,
9608  fkconstraint->initdeferred,
9609  fkconstraint->initially_valid,
9610  parentConstr,
9611  partitionId,
9612  mapped_fkattnum,
9613  numfks,
9614  numfks,
9615  InvalidOid,
9616  indexOid,
9617  RelationGetRelid(pkrel),
9618  pkattnum,
9619  pfeqoperators,
9620  ppeqoperators,
9621  ffeqoperators,
9622  numfks,
9623  fkconstraint->fk_upd_action,
9624  fkconstraint->fk_del_action,
9625  fkconstraint->fk_matchtype,
9626  NULL,
9627  NULL,
9628  NULL,
9629  false,
9630  1,
9631  false,
9632  false);
9633 
9634  /*
9635  * Give this constraint partition-type dependencies on the parent
9636  * constraint as well as the table.
9637  */
9638  ObjectAddressSet(address, ConstraintRelationId, constrOid);
9639  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9640  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
9641  ObjectAddressSet(referenced, RelationRelationId, partitionId);
9642  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
9643 
9644  /* Make all this visible before recursing */
9646 
9647  /* call ourselves to finalize the creation and we're done */
9648  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
9649  indexOid,
9650  constrOid,
9651  numfks,
9652  pkattnum,
9653  mapped_fkattnum,
9654  pfeqoperators,
9655  ppeqoperators,
9656  ffeqoperators,
9657  old_check_ok,
9658  lockmode);
9659 
9660  table_close(partition, NoLock);
9661  }
9662  }
9663 }
#define NIL
Definition: pg_list.h:65
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:11180
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
char * name
Definition: tablecmds.c:201
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8660
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define RelationGetDescr(relation)
Definition: rel.h:483
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1106
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, bool old_check_ok, LOCKMODE lockmode)
Definition: tablecmds.c:9483
char fk_matchtype
Definition: parsenodes.h:2267
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, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:50
Node * qual
Definition: tablecmds.c:206
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
bool initdeferred
Definition: parsenodes.h:2235
PartitionDesc RelationGetPartitionDesc(Relation rel, bool include_detached)
Definition: partdesc.c:65
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
char * conname
Definition: parsenodes.h:2233
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
List * constraints
Definition: tablecmds.c:175
Definition: attmap.h:34
static bool tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop)
Definition: tablecmds.c:10080
#define ERROR
Definition: elog.h:46
bool deferrable
Definition: parsenodes.h:2234
#define lfirst_node(type, lc)
Definition: pg_list.h:172
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:491
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5948
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3943
#define AssertArg(condition)
Definition: c.h:806
List * lappend(List *list, void *datum)
Definition: list.c:336
ConstrType contype
Definition: tablecmds.c:202
void * palloc0(Size size)
Definition: mcxt.c:1093
void CommandCounterIncrement(void)
Definition: xact.c:1021
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2276
#define ereport(elevel,...)
Definition: elog.h:157
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:174
char fk_del_action
Definition: parsenodes.h:2269
AttrNumber * attnums
Definition: attmap.h:36
#define INDEX_MAX_KEYS
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4442
int errmsg(const char *fmt,...)
Definition: elog.c:909
int i
#define copyObject(obj)
Definition: nodes.h:655
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
bool skip_validation
Definition: parsenodes.h:2275
#define RelationGetRelid(relation)
Definition: rel.h:457
List * fk_attrs
Definition: parsenodes.h:2265
char fk_upd_action
Definition: parsenodes.h:2268
#define RelationGetNamespace(relation)
Definition: rel.h:498

◆ AlterIndexNamespaces()

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

Definition at line 15831 of file tablecmds.c.

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

Referenced by AlterTableNamespaceInternal().

15833 {
15834  List *indexList;
15835  ListCell *l;
15836 
15837  indexList = RelationGetIndexList(rel);
15838 
15839  foreach(l, indexList)
15840  {
15841  Oid indexOid = lfirst_oid(l);
15842  ObjectAddress thisobj;
15843 
15844  thisobj.classId = RelationRelationId;
15845  thisobj.objectId = indexOid;
15846  thisobj.objectSubId = 0;
15847 
15848  /*
15849  * Note: currently, the index will not have its own dependency on the
15850  * namespace, so we don't need to do changeDependencyFor(). There's no
15851  * row type in pg_type, either.
15852  *
15853  * XXX this objsMoved test may be pointless -- surely we have a single
15854  * dependency link from a relation to each index?
15855  */
15856  if (!object_address_present(&thisobj, objsMoved))
15857  {
15858  AlterRelationNamespaceInternal(classRel, indexOid,
15859  oldNspOid, newNspOid,
15860  false, objsMoved);
15861  add_exact_object_address(&thisobj, objsMoved);
15862  }
15863  }
15864 
15865  list_free(indexList);
15866 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2681
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2621
unsigned int Oid
Definition: postgres_ext.h:31
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15761
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4551
void list_free(List *list)
Definition: list.c:1391
Definition: pg_list.h:50
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ AlterRelationNamespaceInternal()

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

Definition at line 15761 of file tablecmds.c.

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

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

15765 {
15766  HeapTuple classTup;
15767  Form_pg_class classForm;
15768  ObjectAddress thisobj;
15769  bool already_done = false;
15770 
15771  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
15772  if (!HeapTupleIsValid(classTup))
15773  elog(ERROR, "cache lookup failed for relation %u", relOid);
15774  classForm = (Form_pg_class) GETSTRUCT(classTup);
15775 
15776  Assert(classForm->relnamespace == oldNspOid);
15777 
15778  thisobj.classId = RelationRelationId;
15779  thisobj.objectId = relOid;
15780  thisobj.objectSubId = 0;
15781 
15782  /*
15783  * If the object has already been moved, don't move it again. If it's
15784  * already in the right place, don't move it, but still fire the object
15785  * access hook.
15786  */
15787  already_done = object_address_present(&thisobj, objsMoved);
15788  if (!already_done && oldNspOid != newNspOid)
15789  {
15790  /* check for duplicate name (more friendly than unique-index failure) */
15791  if (get_relname_relid(NameStr(classForm->relname),
15792  newNspOid) != InvalidOid)
15793  ereport(ERROR,
15794  (errcode(ERRCODE_DUPLICATE_TABLE),
15795  errmsg("relation \"%s\" already exists in schema \"%s\"",
15796  NameStr(classForm->relname),
15797  get_namespace_name(newNspOid))));
15798 
15799  /* classTup is a copy, so OK to scribble on */
15800  classForm->relnamespace = newNspOid;
15801 
15802  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
15803 
15804  /* Update dependency on schema if caller said so */
15805  if (hasDependEntry &&
15806  changeDependencyFor(RelationRelationId,
15807  relOid,
15808  NamespaceRelationId,
15809  oldNspOid,
15810  newNspOid) != 1)
15811  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
15812  NameStr(classForm->relname));
15813  }
15814  if (!already_done)
15815  {
15816  add_exact_object_address(&thisobj, objsMoved);
15817 
15818  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
15819  }
15820 
15821  heap_freetuple(classTup);
15822 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2681
int errcode(int sqlerrcode)
Definition: elog.c:698
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2621
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1856
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
int errmsg(const char *fmt,...)
Definition: elog.c:909
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:419
#define elog(elevel,...)
Definition: elog.h:232
#define NameStr(name)
Definition: c.h:681

◆ AlterSeqNamespaces()

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

Definition at line 15876 of file tablecmds.c.

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

Referenced by AlterTableNamespaceInternal().

15879 {
15880  Relation depRel;
15881  SysScanDesc scan;
15882  ScanKeyData key[2];
15883  HeapTuple tup;
15884 
15885  /*
15886  * SERIAL sequences are those having an auto dependency on one of the
15887  * table's columns (we don't care *which* column, exactly).
15888  */
15889  depRel = table_open(DependRelationId, AccessShareLock);
15890 
15891  ScanKeyInit(&key[0],
15892  Anum_pg_depend_refclassid,
15893  BTEqualStrategyNumber, F_OIDEQ,
15894  ObjectIdGetDatum(RelationRelationId));
15895  ScanKeyInit(&key[1],
15896  Anum_pg_depend_refobjid,
15897  BTEqualStrategyNumber, F_OIDEQ,
15899  /* we leave refobjsubid unspecified */
15900 
15901  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
15902  NULL, 2, key);
15903 
15904  while (HeapTupleIsValid(tup = systable_getnext(scan)))
15905  {
15906  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
15907  Relation seqRel;
15908 
15909  /* skip dependencies other than auto dependencies on columns */
15910  if (depForm->refobjsubid == 0 ||
15911  depForm->classid != RelationRelationId ||
15912  depForm->objsubid != 0 ||
15913  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
15914  continue;
15915 
15916  /* Use relation_open just in case it's an index */
15917  seqRel = relation_open(depForm->objid, lockmode);
15918 
15919  /* skip non-sequence relations */
15920  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
15921  {
15922  /* No need to keep the lock */
15923  relation_close(seqRel, lockmode);
15924  continue;
15925  }
15926 
15927  /* Fix the pg_class and pg_depend entries */
15928  AlterRelationNamespaceInternal(classRel, depForm->objid,
15929  oldNspOid, newNspOid,
15930  true, objsMoved);
15931 
15932  /*
15933  * Sequences used to have entries in pg_type, but no longer do. If we
15934  * ever re-instate that, we'll need to move the pg_type entry to the
15935  * new namespace, too (using AlterTypeNamespaceInternal).
15936  */
15937  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
15938 
15939  /* Now we can close it. Keep the lock till end of transaction. */
15940  relation_close(seqRel, NoLock);
15941  }
15942 
15943  systable_endscan(scan);
15944 
15946 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:595
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
#define RelationGetForm(relation)
Definition: rel.h:451
#define AccessShareLock
Definition: lockdefs.h:36
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:383
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:502
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:76
#define DependReferenceIndexId
Definition: pg_depend.h:83
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:804
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15761
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:457
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ AlterTable()

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

Definition at line 4027 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

4029 {
4030  Relation rel;
4031 
4032  /* Caller is required to provide an adequate lock. */
4033  rel = relation_open(context->relid, NoLock);
4034 
4035  CheckTableNotInUse(rel, "ALTER TABLE");
4036 
4037  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4038 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4375
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3943
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1859

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4101 of file tablecmds.c.

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

Referenced by AlterTableInternal(), and ProcessUtilitySlow().

4102 {
4103  /*
4104  * This only works if we read catalog tables using MVCC snapshots.
4105  */
4106  ListCell *lcmd;
4108 
4109  foreach(lcmd, cmds)
4110  {
4111  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4112  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4113 
4114  switch (cmd->subtype)
4115  {
4116  /*
4117  * These subcommands rewrite the heap, so require full locks.
4118  */
4119  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4120  * to SELECT */
4121  case AT_SetTableSpace: /* must rewrite heap */
4122  case AT_AlterColumnType: /* must rewrite heap */
4123  cmd_lockmode = AccessExclusiveLock;
4124  break;
4125 
4126  /*
4127  * These subcommands may require addition of toast tables. If
4128  * we add a toast table to a table currently being scanned, we
4129  * might miss data added to the new toast table by concurrent
4130  * insert transactions.
4131  */
4132  case AT_SetStorage: /* may add toast tables, see
4133  * ATRewriteCatalogs() */
4134  cmd_lockmode = AccessExclusiveLock;
4135  break;
4136 
4137  /*
4138  * Removing constraints can affect SELECTs that have been
4139  * optimized assuming the constraint holds true. See also
4140  * CloneFkReferenced.
4141  */
4142  case AT_DropConstraint: /* as DROP INDEX */
4143  case AT_DropNotNull: /* may change some SQL plans */
4144  cmd_lockmode = AccessExclusiveLock;
4145  break;
4146 
4147  /*
4148  * Subcommands that may be visible to concurrent SELECTs
4149  */
4150  case AT_DropColumn: /* change visible to SELECT */
4151  case AT_AddColumnToView: /* CREATE VIEW */
4152  case AT_DropOids: /* used to equiv to DropColumn */
4153  case AT_EnableAlwaysRule: /* may change SELECT rules */
4154  case AT_EnableReplicaRule: /* may change SELECT rules */
4155  case AT_EnableRule: /* may change SELECT rules */
4156  case AT_DisableRule: /* may change SELECT rules */
4157  cmd_lockmode = AccessExclusiveLock;
4158  break;
4159 
4160  /*
4161  * Changing owner may remove implicit SELECT privileges
4162  */
4163  case AT_ChangeOwner: /* change visible to SELECT */
4164  cmd_lockmode = AccessExclusiveLock;
4165  break;
4166 
4167  /*
4168  * Changing foreign table options may affect optimization.
4169  */
4170  case AT_GenericOptions:
4172  cmd_lockmode = AccessExclusiveLock;
4173  break;
4174 
4175  /*
4176  * These subcommands affect write operations only.
4177  */
4178  case AT_EnableTrig:
4179  case AT_EnableAlwaysTrig:
4180  case AT_EnableReplicaTrig:
4181  case AT_EnableTrigAll:
4182  case AT_EnableTrigUser:
4183  case AT_DisableTrig:
4184  case AT_DisableTrigAll:
4185  case AT_DisableTrigUser:
4186  cmd_lockmode = ShareRowExclusiveLock;
4187  break;
4188 
4189  /*
4190  * These subcommands affect write operations only. XXX
4191  * Theoretically, these could be ShareRowExclusiveLock.
4192  */
4193  case AT_ColumnDefault:
4195  case AT_AlterConstraint:
4196  case AT_AddIndex: /* from ADD CONSTRAINT */
4197  case AT_AddIndexConstraint:
4198  case AT_ReplicaIdentity:
4199  case AT_SetNotNull:
4200  case AT_EnableRowSecurity:
4201  case AT_DisableRowSecurity:
4202  case AT_ForceRowSecurity:
4203  case AT_NoForceRowSecurity:
4204  case AT_AddIdentity:
4205  case AT_DropIdentity:
4206  case AT_SetIdentity:
4207  case AT_DropExpression:
4208  case AT_SetCompression:
4209  cmd_lockmode = AccessExclusiveLock;
4210  break;
4211 
4212  case AT_AddConstraint:
4213  case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
4214  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4215  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4216  if (IsA(cmd->def, Constraint))
4217  {
4218  Constraint *con = (Constraint *) cmd->def;
4219 
4220  switch (con->contype)
4221  {
4222  case CONSTR_EXCLUSION:
4223  case CONSTR_PRIMARY:
4224  case CONSTR_UNIQUE:
4225 
4226  /*
4227  * Cases essentially the same as CREATE INDEX. We
4228  * could reduce the lock strength to ShareLock if
4229  * we can work out how to allow concurrent catalog
4230  * updates. XXX Might be set down to
4231  * ShareRowExclusiveLock but requires further
4232  * analysis.
4233  */
4234  cmd_lockmode = AccessExclusiveLock;
4235  break;
4236  case CONSTR_FOREIGN:
4237 
4238  /*
4239  * We add triggers to both tables when we add a
4240  * Foreign Key, so the lock level must be at least
4241  * as strong as CREATE TRIGGER.
4242  */
4243  cmd_lockmode = ShareRowExclusiveLock;
4244  break;
4245 
4246  default:
4247  cmd_lockmode = AccessExclusiveLock;
4248  }
4249  }
4250  break;
4251 
4252  /*
4253  * These subcommands affect inheritance behaviour. Queries
4254  * started before us will continue to see the old inheritance
4255  * behaviour, while queries started after we commit will see
4256  * new behaviour. No need to prevent reads or writes to the
4257  * subtable while we hook it up though. Changing the TupDesc
4258  * may be a problem, so keep highest lock.
4259  */
4260  case AT_AddInherit:
4261  case AT_DropInherit:
4262  cmd_lockmode = AccessExclusiveLock;
4263  break;
4264 
4265  /*
4266  * These subcommands affect implicit row type conversion. They
4267  * have affects similar to CREATE/DROP CAST on queries. don't
4268  * provide for invalidating parse trees as a result of such
4269  * changes, so we keep these at AccessExclusiveLock.
4270  */
4271  case AT_AddOf:
4272  case AT_DropOf:
4273  cmd_lockmode = AccessExclusiveLock;
4274  break;
4275 
4276  /*
4277  * Only used by CREATE OR REPLACE VIEW which must conflict
4278  * with an SELECTs currently using the view.
4279  */
4280  case AT_ReplaceRelOptions:
4281  cmd_lockmode = AccessExclusiveLock;
4282  break;
4283 
4284  /*
4285  * These subcommands affect general strategies for performance
4286  * and maintenance, though don't change the semantic results
4287  * from normal data reads and writes. Delaying an ALTER TABLE
4288  * behind currently active writes only delays the point where
4289  * the new strategy begins to take effect, so there is no
4290  * benefit in waiting. In this case the minimum restriction
4291  * applies: we don't currently allow concurrent catalog
4292  * updates.
4293  */
4294  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4295  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4296  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4297  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4298  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4299  cmd_lockmode = ShareUpdateExclusiveLock;
4300  break;
4301 
4302  case AT_SetLogged:
4303  case AT_SetUnLogged:
4304  cmd_lockmode = AccessExclusiveLock;
4305  break;
4306 
4307  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4308  cmd_lockmode = ShareUpdateExclusiveLock;
4309  break;
4310 
4311  /*
4312  * Rel options are more complex than first appears. Options
4313  * are set here for tables, views and indexes; for historical
4314  * reasons these can all be used with ALTER TABLE, so we can't
4315  * decide between them using the basic grammar.
4316  */
4317  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4318  * getTables() */
4319  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4320  * getTables() */
4321  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4322  break;
4323 
4324  case AT_AttachPartition:
4325  cmd_lockmode = ShareUpdateExclusiveLock;
4326  break;
4327 
4328  case AT_DetachPartition:
4329  if (((PartitionCmd *) cmd->def)->concurrent)
4330  cmd_lockmode = ShareUpdateExclusiveLock;
4331  else
4332  cmd_lockmode = AccessExclusiveLock;
4333  break;
4334 
4336  cmd_lockmode = ShareUpdateExclusiveLock;
4337  break;
4338 
4339  case AT_CheckNotNull:
4340 
4341  /*
4342  * This only examines the table's schema; but lock must be
4343  * strong enough to prevent concurrent DROP NOT NULL.
4344  */
4345  cmd_lockmode = AccessShareLock;
4346  break;
4347 
4349  cmd_lockmode = AccessExclusiveLock;
4350  break;
4351 
4352  default: /* oops */
4353  elog(ERROR, "unrecognized alter table type: %d",
4354  (int) cmd->subtype);
4355  break;
4356  }
4357 
4358  /*
4359  * Take the greatest lockmode from any subcommand
4360  */
4361  if (cmd_lockmode > lockmode)
4362  lockmode = cmd_lockmode;
4363  }
4364 
4365  return lockmode;
4366 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
int LOCKMODE
Definition: lockdefs.h:26
#define AccessShareLock
Definition: lockdefs.h:36
AlterTableType subtype
Definition: parsenodes.h:1950
#define ERROR
Definition: elog.h:46
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define lfirst(lc)
Definition: pg_list.h:169
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2084
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define elog(elevel,...)
Definition: elog.h:232
ConstrType contype
Definition: parsenodes.h:2230
Definition: pg_list.h:50

◆ AlterTableInternal()

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

Definition at line 4056 of file tablecmds.c.

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

4057 {
4058  Relation rel;
4059  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4060 
4061  rel = relation_open(relid, lockmode);
4062 
4064 
4065  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4066 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4375
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4101
void EventTriggerAlterTableRelid(Oid objectId)

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3971 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3972 {
3973  return RangeVarGetRelidExtended(stmt->relation, lockmode,
3974  stmt->missing_ok ? RVR_MISSING_OK : 0,
3976  (void *) stmt);
3977 }
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:16275
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
RangeVar * relation
Definition: parsenodes.h:1859

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 13835 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

13836 {
13837  List *relations = NIL;
13838  ListCell *l;
13839  ScanKeyData key[1];
13840  Relation rel;
13841  TableScanDesc scan;
13842  HeapTuple tuple;
13843  Oid orig_tablespaceoid;
13844  Oid new_tablespaceoid;
13845  List *role_oids = roleSpecsToIds(stmt->roles);
13846 
13847  /* Ensure we were not asked to move something we can't */
13848  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
13849  stmt->objtype != OBJECT_MATVIEW)
13850  ereport(ERROR,
13851  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13852  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
13853 
13854  /* Get the orig and new tablespace OIDs */
13855  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
13856  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
13857 
13858  /* Can't move shared relations in to or out of pg_global */
13859  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
13860  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
13861  new_tablespaceoid == GLOBALTABLESPACE_OID)
13862  ereport(ERROR,
13863  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13864  errmsg("cannot move relations in to or out of pg_global tablespace")));
13865 
13866  /*
13867  * Must have CREATE rights on the new tablespace, unless it is the
13868  * database default tablespace (which all users implicitly have CREATE
13869  * rights on).
13870  */
13871  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
13872  {
13873  AclResult aclresult;
13874 
13875  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
13876  ACL_CREATE);
13877  if (aclresult != ACLCHECK_OK)
13878  aclcheck_error(aclresult, OBJECT_TABLESPACE,
13879  get_tablespace_name(new_tablespaceoid));
13880  }
13881 
13882  /*
13883  * Now that the checks are done, check if we should set either to
13884  * InvalidOid because it is our database's default tablespace.
13885  */
13886  if (orig_tablespaceoid == MyDatabaseTableSpace)
13887  orig_tablespaceoid = InvalidOid;
13888 
13889  if (new_tablespaceoid == MyDatabaseTableSpace)
13890  new_tablespaceoid = InvalidOid;
13891 
13892  /* no-op */
13893  if (orig_tablespaceoid == new_tablespaceoid)
13894  return new_tablespaceoid;
13895 
13896  /*
13897  * Walk the list of objects in the tablespace and move them. This will
13898  * only find objects in our database, of course.
13899  */
13900  ScanKeyInit(&key[0],
13901  Anum_pg_class_reltablespace,
13902  BTEqualStrategyNumber, F_OIDEQ,
13903  ObjectIdGetDatum(orig_tablespaceoid));
13904 
13905  rel = table_open(RelationRelationId, AccessShareLock);
13906  scan = table_beginscan_catalog(rel, 1, key);
13907  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
13908  {
13909  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
13910  Oid relOid = relForm->oid;
13911 
13912  /*
13913  * Do not move objects in pg_catalog as part of this, if an admin
13914  * really wishes to do so, they can issue the individual ALTER
13915  * commands directly.
13916  *
13917  * Also, explicitly avoid any shared tables, temp tables, or TOAST
13918  * (TOAST will be moved with the main table).
13919  */
13920  if (IsCatalogNamespace(relForm->relnamespace) ||
13921  relForm->relisshared ||
13922  isAnyTempNamespace(relForm->relnamespace) ||
13923  IsToastNamespace(relForm->relnamespace))
13924  continue;
13925 
13926  /* Only move the object type requested */
13927  if ((stmt->objtype == OBJECT_TABLE &&
13928  relForm->relkind != RELKIND_RELATION &&
13929  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
13930  (stmt->objtype == OBJECT_INDEX &&
13931  relForm->relkind != RELKIND_INDEX &&
13932  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
13933  (stmt->objtype == OBJECT_MATVIEW &&
13934  relForm->relkind != RELKIND_MATVIEW))
13935  continue;
13936 
13937  /* Check if we are only moving objects owned by certain roles */
13938  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
13939  continue;
13940 
13941  /*
13942  * Handle permissions-checking here since we are locking the tables
13943  * and also to avoid doing a bunch of work only to fail part-way. Note
13944  * that permissions will also be checked by AlterTableInternal().
13945  *
13946  * Caller must be considered an owner on the table to move it.
13947  */
13948  if (!pg_class_ownercheck(relOid, GetUserId()))
13950  NameStr(relForm->relname));
13951 
13952  if (stmt->nowait &&
13954  ereport(ERROR,
13955  (errcode(ERRCODE_OBJECT_IN_USE),
13956  errmsg("aborting because lock on relation \"%s.%s\" is not available",
13957  get_namespace_name(relForm->relnamespace),
13958  NameStr(relForm->relname))));
13959  else
13961 
13962  /* Add to our list of objects to move */
13963  relations = lappend_oid(relations, relOid);
13964  }
13965 
13966  table_endscan(scan);
13968 
13969  if (relations == NIL)
13970  ereport(NOTICE,
13971  (errcode(ERRCODE_NO_DATA_FOUND),
13972  errmsg("no matching relations in tablespace \"%s\" found",
13973  orig_tablespaceoid == InvalidOid ? "(database default)" :
13974  get_tablespace_name(orig_tablespaceoid))));
13975 
13976  /* Everything is locked, loop through and move all of the relations. */
13977  foreach(l, relations)
13978  {
13979  List *cmds = NIL;
13981 
13982  cmd->subtype = AT_SetTableSpace;
13983  cmd->name = stmt->new_tablespacename;
13984 
13985  cmds = lappend(cmds, cmd);
13986 
13988  /* OID is set by AlterTableInternal */
13989  AlterTableInternal(lfirst_oid(l), cmds, false);
13991  }
13992 
13993  return new_tablespaceoid;
13994 }
#define NIL
Definition: pg_list.h:65
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:152
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1433
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4773
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
Oid GetUserId(void)
Definition: miscinit.c:478
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1974
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
AlterTableType subtype
Definition: parsenodes.h:1950
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:200
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
#define OidIsValid(objectId)
Definition: c.h:710
Oid MyDatabaseTableSpace
Definition: globals.c:90
void EventTriggerAlterTableStart(Node *parsetree)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3313
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define ACL_CREATE
Definition: parsenodes.h:92
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1340
List * lappend(List *list, void *datum)
Definition: list.c:336
AclResult
Definition: acl.h:177
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:587
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1436
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:689
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4823
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:182
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:991
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4056
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:909
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1479
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:681
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3194
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:109
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:171
void EventTriggerAlterTableEnd(void)

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 15651 of file tablecmds.c.

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

Referenced by ExecAlterObjectSchemaStmt().

15652 {
15653  Relation rel;
15654  Oid relid;
15655  Oid oldNspOid;
15656  Oid nspOid;
15657  RangeVar *newrv;
15658  ObjectAddresses *objsMoved;
15659  ObjectAddress myself;
15660 
15662  stmt->missing_ok ? RVR_MISSING_OK : 0,
15664  (void *) stmt);
15665 
15666  if (!OidIsValid(relid))
15667  {
15668  ereport(NOTICE,
15669  (errmsg("relation \"%s\" does not exist, skipping",
15670  stmt->relation->relname)));
15671  return InvalidObjectAddress;
15672  }
15673 
15674  rel = relation_open(relid, NoLock);
15675 
15676  oldNspOid = RelationGetNamespace(rel);
15677 
15678  /* If it's an owned sequence, disallow moving it by itself. */
15679  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
15680  {
15681  Oid tableId;
15682  int32 colId;
15683 
15684  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
15685  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
15686  ereport(ERROR,
15687  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15688  errmsg("cannot move an owned sequence into another schema"),
15689  errdetail("Sequence \"%s\" is linked to table \"%s\".",
15691  get_rel_name(tableId))));
15692  }
15693 
15694  /* Get and lock schema OID and check its permissions. */
15695  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
15696  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
15697 
15698  /* common checks on switching namespaces */
15699  CheckSetNamespace(oldNspOid, nspOid);
15700 
15701  objsMoved = new_object_addresses();
15702  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
15703  free_object_addresses(objsMoved);
15704 
15705  ObjectAddressSet(myself, RelationRelationId, relid);
15706 
15707  if (oldschema)
15708  *oldschema = oldNspOid;
15709 
15710  /* close rel, but keep lock until commit */
15711  relation_close(rel, NoLock);
15712 
15713  return myself;
15714 }
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:828
int errcode(int sqlerrcode)
Definition: elog.c:698
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2566
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2862
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
signed int int32
Definition: c.h:429
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:46
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15722
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:16275
int errdetail(const char *fmt,...)
Definition: elog.c:1042
#define RelationGetRelationName(relation)
Definition: rel.h:491
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2966
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:534
#define ereport(elevel,...)
Definition: elog.h:157
#define NOTICE
Definition: elog.h:37
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:909
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1899
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:422
#define RelationGetNamespace(relation)
Definition: rel.h:498

◆ AlterTableNamespaceInternal()

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

Definition at line 15722 of file tablecmds.c.

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

15724 {
15725  Relation classRel;
15726 
15727  Assert(objsMoved != NULL);
15728 
15729  /* OK, modify the pg_class row and pg_depend entry */
15730  classRel = table_open(RelationRelationId, RowExclusiveLock);
15731 
15732  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
15733  nspOid, true, objsMoved);
15734 
15735  /* Fix the table's row type too, if it has one */
15736  if (OidIsValid(rel->rd_rel->reltype))
15737  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
15738  nspOid, false, false, objsMoved);
15739 
15740  /* Fix other dependent stuff */
15741  if (rel->rd_rel->relkind == RELKIND_RELATION ||
15742  rel->rd_rel->relkind == RELKIND_MATVIEW ||
15743  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15744  {
15745  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
15746  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
15747  objsMoved, AccessExclusiveLock);
15748  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
15749  false, objsMoved);
15750  }
15751 
15752  table_close(classRel, RowExclusiveLock);
15753 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3970
Form_pg_class rd_rel
Definition: rel.h:110
#define OidIsValid(objectId)
Definition: c.h:710
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15831
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:15876
#define RowExclusiveLock
Definition: lockdefs.h:38
#define Assert(condition)
Definition: c.h:804
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15761
#define AccessExclusiveLock
Definition: lockdefs.h:45
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:457

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

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

Referenced by ATExecAddConstraint(), and DetachAddConstraintIfNeeded().

8705 {
8706  List *newcons;
8707  ListCell *lcon;
8708  List *children;
8709  ListCell *child;
8711 
8712  /* At top level, permission check was done in ATPrepCmd, else do it */
8713  if (recursing)
8715 
8716  /*
8717  * Call AddRelationNewConstraints to do the work, making sure it works on
8718  * a copy of the Constraint so transformExpr can't modify the original. It
8719  * returns a list of cooked constraints.
8720  *
8721  * If the constraint ends up getting merged with a pre-existing one, it's
8722  * omitted from the returned list, which is what we want: we do not need
8723  * to do any validation work. That can only happen at child tables,
8724  * though, since we disallow merging at the top level.
8725  */
8726  newcons = AddRelationNewConstraints(rel, NIL,
8727  list_make1(copyObject(constr)),
8728  recursing | is_readd, /* allow_merge */
8729  !recursing, /* is_local */
8730  is_readd, /* is_internal */
8731  NULL); /* queryString not available
8732  * here */
8733 
8734  /* we don't expect more than one constraint here */
8735  Assert(list_length(newcons) <= 1);
8736 
8737  /* Add each to-be-validated constraint to Phase 3's queue */
8738  foreach(lcon, newcons)
8739  {
8740  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
8741 
8742  if (!ccon->skip_validation)
8743  {
8744  NewConstraint *newcon;
8745 
8746  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
8747  newcon->name = ccon->name;
8748  newcon->contype = ccon->contype;
8749  newcon->qual = ccon->expr;
8750 
8751  tab->constraints = lappend(tab->constraints, newcon);
8752  }
8753 
8754  /* Save the actually assigned name if it was defaulted */
8755  if (constr->conname == NULL)
8756  constr->conname = ccon->name;
8757 
8758  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
8759  }
8760 
8761  /* At this point we must have a locked-down name to use */
8762  Assert(constr->conname != NULL);
8763 
8764  /* Advance command counter in case same table is visited multiple times */
8766 
8767  /*
8768  * If the constraint got merged with an existing constraint, we're done.
8769  * We mustn't recurse to child tables in this case, because they've
8770  * already got the constraint, and visiting them again would lead to an
8771  * incorrect value for coninhcount.
8772  */
8773  if (newcons == NIL)
8774  return address;
8775 
8776  /*
8777  * If adding a NO INHERIT constraint, no need to find our children.
8778  */
8779  if (constr->is_no_inherit)
8780  return address;
8781 
8782  /*
8783  * Propagate to children as appropriate. Unlike most other ALTER
8784  * routines, we have to do this one level of recursion at a time; we can't
8785  * use find_all_inheritors to do it in one pass.
8786  */
8787  children =
8788  find_inheritance_children(RelationGetRelid(rel), false, lockmode);
8789 
8790  /*
8791  * Check if ONLY was specified with ALTER TABLE. If so, allow the
8792  * constraint creation only if there are no children currently. Error out
8793  * otherwise.
8794  */
8795  if (!recurse && children != NIL)
8796  ereport(ERROR,
8797  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8798  errmsg("constraint must be added to child tables too")));
8799 
8800  foreach(child, children)
8801  {
8802  Oid childrelid = lfirst_oid(child);
8803  Relation childrel;
8804  AlteredTableInfo *childtab;
8805 
8806  /* find_inheritance_children already got lock */
8807  childrel = table_open(childrelid, NoLock);
8808  CheckTableNotInUse(childrel, "ALTER TABLE");
8809 
8810  /* Find or create work queue entry for this table */
8811  childtab = ATGetQueueEntry(wqueue, childrel);
8812 
8813  /* Recurse to child */
8814  ATAddCheckConstraint(wqueue, childtab, childrel,
8815  constr, recurse, true, is_readd, lockmode);
8816 
8817  table_close(childrel, NoLock);
8818  }
8819 
8820  return address;
8821 }
#define NIL
Definition: pg_list.h:65
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2576
char * name
Definition: tablecmds.c:201
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Node * qual
Definition: tablecmds.c:206
int errcode(int sqlerrcode)
Definition: elog.c:698
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:8702
char * conname
Definition: parsenodes.h:2233
unsigned int Oid
Definition: postgres_ext.h:31
#define ATT_TABLE
Definition: tablecmds.c:306
List * constraints
Definition: tablecmds.c:175
#define list_make1(x1)
Definition: pg_list.h:206
#define ERROR
Definition: elog.h:46
#define NoLock
Definition: lockdefs.h:34
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5948
bool skip_validation
Definition: heap.h:42
ConstrType contype
Definition: heap.h:37
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3943
List * lappend(List *list, void *datum)
Definition: list.c:336
ConstrType contype
Definition: tablecmds.c:202
void * palloc0(Size size)
Definition: mcxt.c:1093
void CommandCounterIncrement(void)
Definition: xact.c:1021
bool is_no_inherit
Definition: parsenodes.h:2239
#define ereport(elevel,...)
Definition: elog.h:157
List * find_inheritance_children(Oid parentrelId, bool include_detached, LOCKMODE lockmode)
Definition: pg_inherits.c:60
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:909
Oid conoid
Definition: heap.h:38
Node * expr
Definition: heap.h:41
static void ATSimplePermissions(Relation rel, int allowed_targets)
Definition: tablecmds.c:5986
#define copyObject(obj)
Definition: nodes.h:655
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:311
char * name
Definition: heap.h:39
#define RelationGetRelid(relation)
Definition: rel.h:457
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ ATAddForeignKeyConstraint()

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

Definition at line 8839 of file tablecmds.c.

References addFkRecurseReferenced(), addFkRecurseReferencing(), allowSystemTableMods, Assert, BTEqualStrategyNumber, can_coerce_type(), checkFkeyPermissions(), CLAOID, COERCION_IMPLICIT, Constraint::conname, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, findFkeyCast(), Constraint::fk_attrs, Constraint::fk_del_action, Constraint::fk_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(), MemSet, 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(), and TupleDescAttr.

Referenced by ATExecAddConstraint().

8842 {
8843  Relation pkrel;
8844  int16 pkattnum[INDEX_MAX_KEYS];
8845  int16 fkattnum[INDEX_MAX_KEYS];
8846  Oid pktypoid[INDEX_MAX_KEYS];
8847  Oid fktypoid[INDEX_MAX_KEYS];
8848  Oid opclasses[INDEX_MAX_KEYS];
8849  Oid pfeqoperators[INDEX_MAX_KEYS];
8850  Oid ppeqoperators[INDEX_MAX_KEYS];
8851  Oid ffeqoperators[INDEX_MAX_KEYS];
8852  int i;
8853  int numfks,
8854  numpks;
8855  Oid indexOid;
8856  bool old_check_ok;
8857  ObjectAddress address;
8858  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
8859 
8860  /*
8861  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
8862  * delete rows out from under us.
8863  */
8864  if (OidIsValid(fkconstraint->old_pktable_oid))
8865  pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
8866  else
8867  pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
8868 
8869  /*
8870  * Validity checks (permission checks wait till we have the column
8871  * numbers)
8872  */
8873  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8874  {
8875  if (!recurse)
8876  ereport(ERROR,
8877  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8878  errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
8880  RelationGetRelationName(pkrel))));
8881  if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
8882  ereport(ERROR,
8883  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8884  errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
8886  RelationGetRelationName(pkrel)),
8887  errdetail("This feature is not yet supported on partitioned tables.")));
8888  }
8889 
8890  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
8891  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
8892  ereport(ERROR,
8893  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8894  errmsg("referenced relation \"%s\" is not a table",
8895  RelationGetRelationName(pkrel))));
8896 
8897  if (!allowSystemTableMods && IsSystemRelation(pkrel))
8898  ereport(ERROR,
8899  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
8900  errmsg("permission denied: \"%s\" is a system catalog",
8901  RelationGetRelationName(pkrel))));
8902 
8903  /*
8904  * References from permanent or unlogged tables to temp tables, and from
8905  * permanent tables to unlogged tables, are disallowed because the
8906  * referenced data can vanish out from under us. References from temp
8907  * tables to any other table type are also disallowed, because other
8908  * backends might need to run the RI triggers on the perm table, but they
8909  * can't reliably see tuples in the local buffers of other backends.
8910  */
8911  switch (rel->rd_rel->relpersistence)
8912  {
8913  case RELPERSISTENCE_PERMANENT:
8914  if (!RelationIsPermanent(pkrel))
8915  ereport(ERROR,
8916  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8917  errmsg("constraints on permanent tables may reference only permanent tables")));
8918  break;
8919  case RELPERSISTENCE_UNLOGGED:
8920  if (!RelationIsPermanent(pkrel)
8921  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
8922  ereport(ERROR,
8923  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8924  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
8925  break;
8926  case RELPERSISTENCE_TEMP:
8927  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
8928  ereport(ERROR,
8929  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8930  errmsg("constraints on temporary tables may reference only temporary tables")));
8931  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
8932  ereport(ERROR,
8933  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8934  errmsg("constraints on temporary tables must involve temporary tables of this session")));
8935  break;
8936  }
8937 
8938  /*
8939  * Look up the referencing attributes to make sure they exist, and record
8940  * their attnums and type OIDs.
8941  */
8942  MemSet(pkattnum, 0, sizeof(pkattnum));
8943  MemSet(fkattnum, 0, sizeof(fkattnum));
8944  MemSet(pktypoid, 0, sizeof(pktypoid));
8945  MemSet(fktypoid, 0, sizeof(fktypoid));
8946  MemSet(opclasses, 0, sizeof(opclasses));
8947  MemSet(pfeqoperators, 0, sizeof(pfeqoperators));
8948  MemSet(ppeqoperators, 0, sizeof(ppeqoperators));
8949  MemSet(ffeqoperators, 0, sizeof(ffeqoperators));
8950 
8952  fkconstraint->fk_attrs,
8953  fkattnum, fktypoid);
8954 
8955  /*
8956  * If the attribute list for the referenced table was omitted, lookup the
8957  * definition of the primary key and use it. Otherwise, validate the
8958  * supplied attribute list. In either case, discover the index OID and
8959  * index opclasses, and the attnums and type OIDs of the attributes.
8960  */
8961  if (fkconstraint->pk_attrs == NIL)
8962  {
8963  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
8964  &fkconstraint->pk_attrs,
8965  pkattnum, pktypoid,
8966  opclasses);
8967  }
8968  else
8969  {
8970  numpks = transformColumnNameList(RelationGetRelid(pkrel),
8971  fkconstraint->pk_attrs,
8972  pkattnum, pktypoid);
8973  /* Look for an index matching the column list */
8974  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
8975  opclasses);
8976  }
8977 
8978  /*
8979  * Now we can check permissions.
8980  */
8981  checkFkeyPermissions(pkrel, pkattnum, numpks);
8982 
8983  /*
8984  * Check some things for generated columns.
8985  */
8986  for (i = 0; i < numfks; i++)
8987  {
8988  char attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
8989 
8990  if (attgenerated)
8991  {
8992  /*
8993  * Check restrictions on UPDATE/DELETE actions, per SQL standard
8994  */
8995  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
8996  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
8997  fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
8998  ereport(ERROR,
8999  (errcode(ERRCODE_SYNTAX_ERROR),
9000  errmsg("invalid %s action for foreign key constraint containing generated column",
9001  "ON UPDATE")));
9002  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
9003  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
9004  ereport(ERROR,
9005  (errcode(ERRCODE_SYNTAX_ERROR),
9006  errmsg("invalid %s action for foreign key constraint containing generated column",
9007  "ON DELETE")));
9008  }
9009  }
9010 
9011  /*
9012  * Look up the equality operators to use in the constraint.
9013  *
9014  * Note that we have to be careful about the difference between the actual
9015  * PK column type and the opclass' declared input type, which might be
9016  * only binary-compatible with it. The declared opcintype is the right
9017  * thing to probe pg_amop with.
9018  */
9019  if (numfks != numpks)
9020  ereport(ERROR,
9021  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
9022  errmsg("number of referencing and referenced columns for foreign key disagree")));
9023 
9024  /*
9025  * On the strength of a previous constraint, we might avoid scanning
9026  * tables to validate this one. See below.
9027  */
9028  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
9029  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
9030 
9031  for (i = 0; i < numpks; i++)
9032  {
9033  Oid pktype = pktypoid[i];
9034  Oid fktype = fktypoid[i];
9035  Oid fktyped;
9036  HeapTuple cla_ht;
9037  Form_pg_opclass cla_tup;
9038  Oid amid;
9039  Oid opfamily;
9040  Oid opcintype;
9041  Oid pfeqop;
9042  Oid ppeqop;
9043  Oid ffeqop;
9044  int16 eqstrategy;
9045  Oid pfeqop_right;
9046 
9047  /* We need several fields out of the pg_opclass entry */
9048  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
9049  if (!HeapTupleIsValid(cla_ht))
9050  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
9051  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
9052  amid = cla_tup->opcmethod;
9053  opfamily = cla_tup->opcfamily;
9054  opcintype = cla_tup->opcintype;
9055  ReleaseSysCache(cla_ht);
9056 
9057  /*
9058  * Check it's a btree; currently this can never fail since no other
9059  * index AMs support unique indexes. If we ever did have other types
9060  * of unique indexes, we'd need a way to determine which operator
9061  * strategy number is equality. (Is it reasonable to insist that
9062  * every such index AM use btree's number for equality?)
9063  */
9064  if (amid != BTREE_AM_OID)
9065  elog(ERROR, "only b-tree indexes are supported for foreign keys");
9066  eqstrategy = BTEqualStrategyNumber;
9067 
9068  /*
9069  * There had better be a primary equality operator for the index.
9070  * We'll use it for PK = PK comparisons.
9071  */
9072  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
9073  eqstrategy);
9074 
9075  if (!OidIsValid(ppeqop))
9076  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
9077  eqstrategy, opcintype, opcintype, opfamily);
9078 
9079  /*
9080  * Are there equality operators that take exactly the FK type? Assume
9081  * we should look through any domain here.
9082  */
9083  fktyped = getBaseType(fktype);
9084 
9085  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
9086  eqstrategy);
9087  if (OidIsValid(pfeqop))
9088  {
9089  pfeqop_right = fktyped;
9090  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
9091  eqstrategy);
9092  }
9093  else
9094  {
9095  /* keep compiler quiet */
9096  pfeqop_right = InvalidOid;
9097  ffeqop = InvalidOid;
9098  }
9099 
9100  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9101  {
9102  /*
9103  * Otherwise, look for an implicit cast from the FK type to the
9104  * opcintype, and if found, use the primary equality operator.
9105  * This is a bit tricky because opcintype might be a polymorphic
9106  * type such as ANYARRAY or ANYENUM; so what we have to test is
9107  * whether the two actual column types can be concurrently cast to
9108  * that type. (Otherwise, we'd fail to reject combinations such
9109  * as int[] and point[].)
9110  */
9111  Oid input_typeids[2];
9112  Oid target_typeids[2];
9113 
9114  input_typeids[0] = pktype;
9115  input_typeids[1] = fktype;
9116  target_typeids[0] = opcintype;
9117  target_typeids[1] = opcintype;
9118  if (can_coerce_type(2, input_typeids, target_typeids,
9120  {
9121  pfeqop = ffeqop = ppeqop;
9122  pfeqop_right = opcintype;
9123  }
9124  }
9125 
9126  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9127  ereport(ERROR,
9128  (errcode(ERRCODE_DATATYPE_MISMATCH),
9129  errmsg("foreign key constraint \"%s\" cannot be implemented",
9130  fkconstraint->conname),
9131  errdetail("Key columns \"%s\" and \"%s\" "
9132  "are of incompatible types: %s and %s.",
9133  strVal(list_nth(fkconstraint->fk_attrs, i)),
9134  strVal(list_nth(fkconstraint->pk_attrs, i)),
9135  format_type_be(fktype),
9136  format_type_be(pktype))));
9137 
9138  if (old_check_ok)
9139  {
9140  /*
9141  * When a pfeqop changes, revalidate the constraint. We could
9142  * permit intra-opfamily changes, but that adds subtle complexity
9143  * without any concrete benefit for core types. We need not
9144  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
9145  */
9146  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
9147  old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
9148  old_pfeqop_item);
9149  }
9150  if (old_check_ok)
9151  {
9152  Oid old_fktype;
9153  Oid new_fktype;
9154  CoercionPathType old_pathtype;
9155  CoercionPathType new_pathtype;
9156  Oid old_castfunc;
9157  Oid new_castfunc;
9159  fkattnum[i] - 1);
9160 
9161  /*
9162  * Identify coercion pathways from each of the old and new FK-side
9163  * column types to the right (foreign) operand type of the pfeqop.
9164  * We may assume that pg_constraint.conkey is not changing.
9165  */
9166  old_fktype = attr->atttypid;
9167  new_fktype = fktype;
9168  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
9169  &old_castfunc);
9170  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
9171  &new_castfunc);
9172 
9173  /*
9174  * Upon a change to the cast from the FK column to its pfeqop
9175  * operand, revalidate the constraint. For this evaluation, a
9176  * binary coercion cast is equivalent to no cast at all. While
9177  * type implementors should design implicit casts with an eye
9178  * toward consistency of operations like equality, we cannot
9179  * assume here that they have done so.
9180  *
9181  * A function with a polymorphic argument could change behavior
9182  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
9183  * when the cast destination is polymorphic, we only avoid
9184  * revalidation if the input type has not changed at all. Given
9185  * just the core data types and operator classes, this requirement
9186  * prevents no would-be optimizations.
9187  *
9188  * If the cast converts from a base type to a domain thereon, then
9189  * that domain type must be the opcintype of the unique index.
9190  * Necessarily, the primary key column must then be of the domain
9191  * type. Since the constraint was previously valid, all values on
9192  * the foreign side necessarily exist on the primary side and in
9193  * turn conform to the domain. Consequently, we need not treat
9194  * domains specially here.
9195  *
9196  * Since we require that all collations share the same notion of
9197  * equality (which they do, because texteq reduces to bitwise
9198  * equality), we don't compare collation here.
9199  *
9200  * We need not directly consider the PK type. It's necessarily
9201  * binary coercible to the opcintype of the unique index column,
9202  * and ri_triggers.c will only deal with PK datums in terms of
9203  * that opcintype. Changing the opcintype also changes pfeqop.
9204  */
9205  old_check_ok = (new_pathtype == old_pathtype &&
9206  new_castfunc == old_castfunc &&
9207  (!IsPolymorphicType(pfeqop_right) ||
9208  new_fktype == old_fktype));
9209  }
9210 
9211  pfeqoperators[i] = pfeqop;
9212  ppeqoperators[i] = ppeqop;
9213  ffeqoperators[i] = ffeqop;
9214  }
9215 
9216  /*
9217  * Create all the constraint and trigger objects, recursing to partitions
9218  * as necessary. First handle the referenced side.
9219  */
9220  address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
9221  indexOid,
9222  InvalidOid, /* no parent constraint */
9223  numfks,
9224  pkattnum,
9225  fkattnum,
9226  pfeqoperators,
9227  ppeqoperators,
9228  ffeqoperators,
9229  old_check_ok);
9230 
9231  /* Now handle the referencing side. */
9232  addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
9233  indexOid,
9234  address.objectId,
9235  numfks,
9236  pkattnum,
9237  fkattnum,
9238  pfeqoperators,
9239  ppeqoperators,
9240  ffeqoperators,
9241  old_check_ok,
9242  lockmode);
9243 
9244  /*
9245  * Done. Close pk table, but keep lock until we've committed.
9246  */
9247  table_close(pkrel, NoLock);
9248 
9249  return address;
9250 }
signed short int16
Definition: c.h:428
#define NIL
Definition: pg_list.h:65
#define RelationIsPermanent(relation)
Definition: rel.h:559
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
List * old_conpfeqop
Definition: parsenodes.h:2270
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
#define RelationGetDescr(relation)
Definition: rel.h:483
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, bool old_check_ok, LOCKMODE lockmode)
Definition: tablecmds.c:9483
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
bool can_coerce_type(int nargs, const Oid *input_typeids, const Oid *target_typeids, CoercionContext ccontext)
Definition: parse_coerce.c:556
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2220
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids)
Definition: tablecmds.c:10570
bool rd_islocaltemp
Definition: rel.h:60
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:698
#define MemSet(start, val, len)
Definition: c.h:1008
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
List * pk_attrs
Definition: parsenodes.h:2266
char * conname
Definition: parsenodes.h:2233
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:10882
#define OidIsValid(objectId)
Definition: c.h:710
CoercionPathType
Definition: parse_coerce.h:24
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, bool old_check_ok)
Definition: tablecmds.c:9278
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
TupleDesc oldDesc
Definition: tablecmds.c:161
#define NoLock
Definition: lockdefs.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:1042
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:164
#define RelationGetRelationName(relation)
Definition: rel.h:491
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:203
Oid old_pktable_oid
Definition: parsenodes.h:2271
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2218
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:102
bool allowSystemTableMods
Definition: globals.c:123
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2276
#define ereport(elevel,...)
Definition: elog.h:157
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
Definition: tablecmds.c:10615
char fk_del_action
Definition: parsenodes.h:2269
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:10853
#define INDEX_MAX_KEYS
static int list_length(const List *l)
Definition: pg_list.h:149
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
Definition: tablecmds.c:10712
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
int i
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
RangeVar * pktable
Definition: parsenodes.h:2264
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2468
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2219
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
bool skip_validation
Definition: parsenodes.h:2275
#define RelationGetRelid(relation)
Definition: rel.h:457
List * fk_attrs
Definition: parsenodes.h:2265
#define BTEqualStrategyNumber
Definition: stratnum.h:31
char fk_upd_action
Definition: parsenodes.h:2268
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ ATCheckPartitionsNotInUse()

static void ATCheckPartitionsNotInUse ( Relation  rel,
LOCKMODE  lockmode 
)
static

Definition at line 6149 of file tablecmds.c.

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

Referenced by ATPrepCmd().

6150 {
6151  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6152  {
6153  List *inh;
6154  ListCell *cell;
6155 
6156  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6157  /* first element is the parent rel; must ignore it */
6158  for_each_from(cell, inh, 1)
6159  {
6160  Relation childrel;
6161 
6162  /* find_all_inheritors already got lock */
6163  childrel = table_open(lfirst_oid(cell), NoLock);
6164  CheckTableNotInUse(childrel, "ALTER TABLE");
6165  table_close(childrel, NoLock);
6166  }
6167  list_free(inh);
6168  }
6169 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Form_pg_class rd_rel
Definition: rel.h:110
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3943
#define for_each_from(cell, lst, N)
Definition: pg_list.h:393
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:201
void list_free(List *list)
Definition: list.c:1391
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:457
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ ATColumnChangeRequiresRewrite()

static bool ATColumnChangeRequiresRewrite ( Node expr,
AttrNumber  varattno 
)
static

Definition at line 11732 of file tablecmds.c.

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

Referenced by ATPrepAlterColumnType().

11733 {
11734  Assert(expr != NULL);
11735 
11736  for (;;)
11737  {
11738  /* only one varno, so no need to check that */
11739  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
11740  return false;
11741  else if (IsA(expr, RelabelType))
11742  expr = (Node *) ((RelabelType *) expr)->arg;
11743  else if (IsA(expr, CoerceToDomain))
11744  {
11745  CoerceToDomain *d = (CoerceToDomain *) expr;
11746 
11748  return true;
11749  expr = (Node *) d->arg;
11750  }
11751  else if (IsA(expr, FuncExpr))
11752  {
11753  FuncExpr *f = (FuncExpr *) expr;
11754 
11755  switch (f->funcid)
11756  {
11757  case F_TIMESTAMPTZ_TIMESTAMP:
11758  case F_TIMESTAMP_TIMESTAMPTZ:
11760  return true;
11761  else
11762  expr = linitial(f->args);
11763  break;
11764  default:
11765  return true;
11766  }
11767  }
11768  else
11769  return true;
11770  }
11771 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
List * args
Definition: primnodes.h:503
Definition: nodes.h:539
Definition: primnodes.h:186
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1391
#define linitial(l)
Definition: pg_list.h:174
Oid funcid
Definition: primnodes.h:495
#define Assert(condition)
Definition: c.h:804
void * arg
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:5480

◆ ATController()

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

Definition at line 4375 of file tablecmds.c.

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

Referenced by AlterTable(), and AlterTableInternal().

4378 {
4379  List *wqueue = NIL;
4380  ListCell *lcmd;
4381 
4382  /* Phase 1: preliminary examination of commands, create work queue */
4383  foreach(lcmd, cmds)
4384  {
4385  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4386 
4387  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4388  }
4389 
4390  /* Close the relation, but keep lock until commit */
4391  relation_close(rel, NoLock);
4392 
4393  /* Phase 2: update system catalogs */
4394  ATRewriteCatalogs(&wqueue, lockmode, context);
4395 
4396  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4397  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4398 }
#define NIL
Definition: pg_list.h:65
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5326
#define NoLock
Definition: lockdefs.h:34
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4410
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define lfirst(lc)
Definition: pg_list.h:169
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4771
Definition: pg_list.h:50

◆ ATDetachCheckNoForeignKeyRefs()

static void ATDetachCheckNoForeignKeyRefs ( Relation  partition)
static

Definition at line 18411 of file tablecmds.c.

References Assert, CONSTROID, elog, ERROR, GetParentedForeignKeyRefs(), GETSTRUCT, HeapTupleIsValid, InvalidOid, lfirst_oid, MemSet, 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().

18412 {
18413  List *constraints;
18414  ListCell *cell;
18415 
18416  constraints = GetParentedForeignKeyRefs(partition);
18417 
18418  foreach(cell, constraints)
18419  {
18420  Oid constrOid = lfirst_oid(cell);
18421  HeapTuple tuple;
18422  Form_pg_constraint constrForm;
18423  Relation rel;
18424  Trigger trig;
18425 
18426  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
18427  if (!HeapTupleIsValid(tuple))
18428  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
18429  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
18430 
18431  Assert(OidIsValid(constrForm->conparentid));
18432  Assert(constrForm->confrelid == RelationGetRelid(partition));
18433 
18434  /* prevent data changes into the referencing table until commit */
18435  rel = table_open(constrForm->conrelid, ShareLock);
18436 
18437  MemSet(&trig, 0, sizeof(trig));
18438  trig.tgoid = InvalidOid;
18439  trig.tgname = NameStr(constrForm->conname);
18441  trig.tgisinternal = true;
18442  trig.tgconstrrelid = RelationGetRelid(partition);
18443  trig.tgconstrindid = constrForm->conindid;
18444  trig.tgconstraint = constrForm->oid;
18445  trig.tgdeferrable = false;
18446  trig.tginitdeferred = false;
18447  /* we needn't fill in remaining fields */
18448 
18449  RI_PartitionRemove_Check(&trig, rel, partition);
18450 
18451  ReleaseSysCache(tuple);
18452 
18453  table_close(rel, NoLock);
18454  }
18455 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
static List * GetParentedForeignKeyRefs(Relation partition)
Definition: tablecmds.c:18358
Oid tgoid
Definition: reltrigger.h:25
bool tgisinternal
Definition: reltrigger.h:31
#define MemSet(start, val, len)
Definition: c.h:1008
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:148
char tgenabled
Definition: reltrigger.h:30
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
Oid tgconstraint
Definition: reltrigger.h:35
char * tgname
Definition: reltrigger.h:27
void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1583
bool tgdeferrable
Definition: reltrigger.h:36
bool tginitdeferred
Definition: reltrigger.h:37
#define NoLock
Definition: lockdefs.h:34
Oid tgconstrrelid
Definition: reltrigger.h:33
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
#define InvalidOid
Definition: postgres_ext.h:36
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
Oid tgconstrindid
Definition: reltrigger.h:34
#define elog(elevel,...)
Definition: elog.h:232
#define ShareLock
Definition: lockdefs.h:41
#define NameStr(name)
Definition: c.h:681
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:457
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 16152 of file tablecmds.c.

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

16154 {
16155  ListCell *cur_item;
16156 
16157  foreach(cur_item, on_commits)
16158  {
16159  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16160 
16161  if (!isCommit && oc->creating_subid == mySubid)
16162  {
16163  /* cur_item must be removed */
16165  pfree(oc);
16166  }
16167  else
16168  {
16169  /* cur_item must be preserved */
16170  if (oc->creating_subid == mySubid)
16171  oc->creating_subid = parentSubid;
16172  if (oc->deleting_subid == mySubid)
16173  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
16174  }
16175  }
16176 }
SubTransactionId creating_subid
Definition: tablecmds.c:120
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
void pfree(void *pointer)
Definition: mcxt.c:1169
static List * on_commits
Definition: tablecmds.c:124
SubTransactionId deleting_subid
Definition: tablecmds.c:121
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:593

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 16120 of file tablecmds.c.

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

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

16121 {
16122  ListCell *cur_item;
16123 
16124  foreach(cur_item, on_commits)
16125  {
16126  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16127 
16128  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
16130  {
16131  /* cur_item must be removed */
16133  pfree(oc);
16134  }
16135  else
16136  {
16137  /* cur_item must be preserved */
16140  }
16141  }
16142 }
SubTransactionId creating_subid
Definition: tablecmds.c:120
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
void pfree(void *pointer)
Definition: mcxt.c:1169
static List * on_commits
Definition: tablecmds.c:124
SubTransactionId deleting_subid
Definition: tablecmds.c:121
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:593

◆ ATExecAddColumn()

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

Definition at line 6458 of file tablecmds.c.

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

Referenced by ATExecCmd().

6463 {
6464  Oid myrelid = RelationGetRelid(rel);
6465  ColumnDef *colDef = castNode(ColumnDef, (*cmd)->def);
6466  bool if_not_exists = (*cmd)->missing_ok;
6467  Relation pgclass,
6468  attrdesc;
6469  HeapTuple reltup;
6470  FormData_pg_attribute attribute;
6471  int newattnum;
6472  char relkind;
6473  HeapTuple typeTuple;
6474  Oid typeOid;
6475  int32 typmod;
6476  Oid collOid;
6477  Form_pg_type tform;
6478  Expr *defval;
6479  List *children;
6480  ListCell *child;
6481  AlterTableCmd *childcmd;
6482  AclResult aclresult;
6483  ObjectAddress address;
6484  TupleDesc tupdesc;
6485  FormData_pg_attribute *aattr[] = {&attribute};
6486 
6487  /* At top level, permission check was done in ATPrepCmd, else do it */
6488  if (recursing)
6490 
6491  if (rel->rd_rel->relispartition && !recursing)
6492  ereport(ERROR,
6493  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6494  errmsg("cannot add column to a partition")));
6495 
6496  attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
6497 
6498  /*
6499  * Are we adding the column to a recursion child? If so, check whether to
6500  * merge with an existing definition for the column. If we do merge, we
6501  * must not recurse. Children will already have the column, and recursing
6502  * into them would mess up attinhcount.
6503  */
6504  if (colDef->inhcount > 0)
6505  {
6506  HeapTuple tuple;
6507 
6508  /* Does child already have a column by this name? */
6509  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
6510  if (HeapTupleIsValid(tuple))
6511  {
6512  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
6513  Oid ctypeId;
6514  int32 ctypmod;
6515  Oid ccollid;
6516 
6517  /* Child column must match on type, typmod, and collation */
6518  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
6519  if (ctypeId != childatt->atttypid ||
6520  ctypmod != childatt->atttypmod)
6521  ereport(ERROR,
6522  (errcode(ERRCODE_DATATYPE_MISMATCH),
6523  errmsg("child table \"%s\" has different type for column \"%s\"",
6524  RelationGetRelationName(rel), colDef->colname)));
6525  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
6526  if (ccollid != childatt->attcollation)
6527  ereport(ERROR,
6528  (errcode(ERRCODE_COLLATION_MISMATCH),
6529  errmsg("child table \"%s\" has different collation for column \"%s\"",
6530  RelationGetRelationName(rel), colDef->colname),
6531  errdetail("\"%s\" versus \"%s\"",
6532  get_collation_name(ccollid),
6533  get_collation_name(childatt->attcollation))));
6534 
6535  /* Bump the existing child att's inhcount */
6536  childatt->attinhcount++;
6537  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
6538 
6539  heap_freetuple(tuple);
6540 
6541  /* Inform the user about the merge */
6542  ereport(NOTICE,
6543  (errmsg("merging definition of column \"%s\" for child \"%s\"",
6544  colDef->colname, RelationGetRelationName(rel))));
6545 
6546  table_close(attrdesc, RowExclusiveLock);
6547  return InvalidObjectAddress;
6548  }
6549  }
6550 
6551  /* skip if the name already exists and if_not_exists is true */
6552  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
6553  {
6554  table_close(attrdesc, RowExclusiveLock);
6555  return InvalidObjectAddress;
6556  }
6557 
6558  /*
6559  * Okay, we need to add the column, so go ahead and do parse
6560  * transformation. This can result in queueing up, or even immediately
6561  * executing, subsidiary operations (such as creation of unique indexes);
6562  * so we mustn't do it until we have made the if_not_exists check.
6563  *
6564  * When recursing, the command was already transformed and we needn't do
6565  * so again. Also, if context isn't given we can't transform. (That
6566  * currently happens only for AT_AddColumnToView; we expect that view.c
6567  * passed us a ColumnDef that doesn't need work.)
6568  */
6569  if (context != NULL && !recursing)
6570  {
6571  *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
6572  cur_pass, context);
6573  Assert(*cmd != NULL);
6574  colDef = castNode(ColumnDef, (*cmd)->def);
6575  }
6576 
6577  /*
6578  * Cannot add identity column if table has children, because identity does
6579  * not inherit. (Adding column and identity separately will work.)
6580  */
6581  if (colDef->identity &&
6582  recurse &&
6583  find_inheritance_children(myrelid, false, NoLock) != NIL)
6584  ereport(ERROR,
6585  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6586  errmsg("cannot recursively add identity column to table that has child tables")));
6587 
6588  pgclass = table_open(RelationRelationId, RowExclusiveLock);
6589 
6590  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
6591  if (!HeapTupleIsValid(reltup))
6592  elog(ERROR, "cache lookup failed for relation %u", myrelid);
6593  relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
6594 
6595  /* Determine the new attribute's number */
6596  newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
6597  if (newattnum > MaxHeapAttributeNumber)
6598  ereport(ERROR,
6599  (errcode(ERRCODE_TOO_MANY_COLUMNS),
6600  errmsg("tables can have at most %d columns",
6602 
6603  typeTuple = typenameType(NULL, colDef->typeName, &typmod);
6604  tform = (Form_pg_type) GETSTRUCT(typeTuple);
6605  typeOid = tform->oid;
6606 
6607  aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
6608  if (aclresult != ACLCHECK_OK)
6609  aclcheck_error_type(aclresult, typeOid);
6610 
6611  collOid = GetColumnDefCollation(NULL, colDef, typeOid);
6612 
6613  /* make sure datatype is legal for a column */
6614  CheckAttributeType(colDef->colname, typeOid, collOid,
6615  list_make1_oid(rel->rd_rel->reltype),
6616  0);
6617 
6618  /* construct new attribute's pg_attribute entry */
6619  attribute.attrelid = myrelid;
6620  namestrcpy(&(attribute.attname), colDef->colname);
6621  attribute.atttypid = typeOid;
6622  attribute.attstattarget = (newattnum > 0) ? -1 : 0;
6623  attribute.attlen = tform->typlen;
6624  attribute.atttypmod = typmod;
6625  attribute.attnum = newattnum;
6626  attribute.attbyval = tform->typbyval;
6627  attribute.attndims = list_length(colDef->typeName->arrayBounds);
6628  attribute.attstorage = tform->typstorage;
6629  attribute.attalign = tform->typalign;
6630  attribute.attnotnull = colDef->is_not_null;
6631  attribute.atthasdef = false;
6632  attribute.atthasmissing = false;
6633  attribute.attidentity = colDef->identity;
6634  attribute.attgenerated = colDef->generated;
6635  attribute.attisdropped = false;
6636  attribute.attislocal = colDef->is_local;
6637  attribute.attinhcount = colDef->inhcount;
6638  attribute.attcollation = collOid;
6639 
6640  /*
6641  * lookup attribute's compression method and store it in the
6642  * attr->attcompression.
6643  */
6644  if (rel->rd_rel->relkind == RELKIND_RELATION ||
6645  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6646  attribute.attcompression = GetAttributeCompression(&attribute,
6647  colDef->compression);
6648  else
6649  attribute.attcompression = InvalidCompressionMethod;
6650 
6651  /* attribute.attacl is handled by InsertPgAttributeTuples() */
6652 
6653  ReleaseSysCache(typeTuple);
6654 
6655  tupdesc = CreateTupleDesc(lengthof(aattr), (FormData_pg_attribute **) &aattr);
6656 
6657  InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
6658 
6659  table_close(attrdesc, RowExclusiveLock);
6660 
6661  /*
6662  * Update pg_class tuple as appropriate
6663  */
6664  ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
6665 
6666  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
6667 
6668  heap_freetuple(reltup);
6669 
6670  /* Post creation hook for new attribute */
6671  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
6672 
6673  table_close(pgclass, RowExclusiveLock);
6674 
6675  /* Make the attribute's catalog entry visible */
6677 
6678  /*
6679  * Store the DEFAULT, if any, in the catalogs
6680  */
6681  if (colDef->raw_default)
6682  {
6683  RawColumnDefault *rawEnt;
6684 
6685  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
6686  rawEnt->attnum = attribute.attnum;
6687  rawEnt->raw_default = copyObject(colDef->raw_default);
6688 
6689  /*
6690  * Attempt to skip a complete table rewrite by storing the specified
6691  * DEFAULT value outside of the heap. This may be disabled inside
6692  * AddRelationNewConstraints if the optimization cannot be applied.
6693  */
6694  rawEnt->missingMode = (!colDef->generated);
6695 
6696  rawEnt->generated = colDef->generated;
6697 
6698  /*
6699  * This function is intended for CREATE TABLE, so it processes a
6700  * _list_ of defaults, but we just do one.
6701  */
6703  false, true, false, NULL);
6704 
6705  /* Make the additional catalog changes visible */
6707 
6708  /*
6709  * Did the request for a missing value work? If not we'll have to do a
6710  * rewrite
6711  */
6712  if (!rawEnt->missingMode)
6714  }
6715 
6716  /*
6717  * Tell Phase 3 to fill in the default expression, if there is one.
6718  *
6719  * If there is no default, Phase 3 doesn't have to do anything, because
6720  * that effectively means that the default is NULL. The heap tuple access
6721  * routines always check for attnum > # of attributes in tuple, and return
6722  * NULL if so, so without any modification of the tuple data we will get
6723  * the effect of NULL values in the new column.
6724  *
6725  * An exception occurs when the new column is of a domain type: the domain
6726  * might have a NOT NULL constraint, or a check constraint that indirectly
6727  * rejects nulls. If there are any domain constraints then we construct
6728  * an explicit NULL default value that will be passed through
6729  * CoerceToDomain processing. (This is a tad inefficient, since it causes
6730  * rewriting the table which we really don't have to do, but the present
6731  * design of domain processing doesn't offer any simple way of checking
6732  * the constraints more directly.)
6733  *
6734  * Note: we use build_column_default, and not just the cooked default
6735  * returned by AddRelationNewConstraints, so that the right thing happens
6736  * when a datatype's default applies.
6737  *
6738  * Note: it might seem that this should happen at the end of Phase 2, so
6739  * that the effects of subsequent subcommands can be taken into account.
6740  * It's intentional that we do it now, though. The new column should be
6741  * filled according to what is said in the ADD COLUMN subcommand, so that
6742  * the effects are the same as if this subcommand had been run by itself
6743  * and the later subcommands had been issued in new ALTER TABLE commands.
6744  *
6745  * We can skip this entirely for relations without storage, since Phase 3
6746  * is certainly not going to touch them. System attributes don't have
6747  * interesting defaults, either.
6748  */
6749  if (RELKIND_HAS_STORAGE(relkind) && attribute.attnum > 0)
6750  {
6751  /*
6752  * For an identity column, we can't use build_column_default(),
6753  * because the sequence ownership isn't set yet. So do it manually.
6754  */
6755  if (colDef->identity)
6756  {
6758 
6759  nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
6760  nve->typeId = typeOid;
6761 
6762  defval = (Expr *) nve;
6763 
6764  /* must do a rewrite for identity columns */
6766  }
6767  else
6768  defval = (Expr *) build_column_default(rel, attribute.attnum);
6769 
6770  if (!defval && DomainHasConstraints(typeOid))
6771  {
6772  Oid baseTypeId;
6773  int32 baseTypeMod;
6774  Oid baseTypeColl;
6775 
6776  baseTypeMod = typmod;
6777  baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
6778  baseTypeColl = get_typcollation(baseTypeId);
6779  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
6780  defval = (Expr *) coerce_to_target_type(NULL,
6781  (Node *) defval,
6782  baseTypeId,
6783  typeOid,
6784  typmod,
6787  -1);
6788  if (defval == NULL) /* should not happen */
6789  elog(ERROR, "failed to coerce base type to domain");
6790  }
6791 
6792  if (defval)
6793  {
6795 
6796  newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
6797  newval->attnum = attribute.attnum;
6798  newval->expr = expression_planner(defval);
6799  newval->is_generated = (colDef->generated != '\0');
6800 
6801  tab->newvals = lappend(tab->newvals, newval);
6802  }
6803 
6804  if (DomainHasConstraints(typeOid))
6806 
6807  if (!TupleDescAttr(rel->rd_att, attribute.attnum - 1)->atthasmissing)
6808  {
6809  /*
6810  * If the new column is NOT NULL, and there is no missing value,
6811  * tell Phase 3 it needs to check for NULLs.
6812  */
6813  tab->verify_new_notnull |= colDef->is_not_null;
6814  }
6815  }
6816 
6817  /*
6818  * Add needed dependency entries for the new column.
6819  */
6820  add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
6821  add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
6822 
6823  /*
6824  * Propagate to children as appropriate. Unlike most other ALTER
6825  * routines, we have to do this one level of recursion at a time; we can't
6826  * use find_all_inheritors to do it in one pass.
6827  */
6828  children =
6829  find_inheritance_children(RelationGetRelid(rel), false, lockmode);
6830 
6831  /*
6832  * If we are told not to recurse, there had better not be any child
6833  * tables; else the addition would put them out of step.
6834  */
6835  if (children && !recurse)
6836  ereport(ERROR,
6837  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6838  errmsg("column must be added to child tables too")));
6839 
6840  /* Children should see column as singly inherited */
6841  if (!recursing)
6842  {
6843  childcmd = copyObject(*cmd);
6844  colDef = castNode(ColumnDef, childcmd->def);
6845  colDef->inhcount = 1;
6846  colDef->is_local = false;
6847  }
6848  else
6849  childcmd = *cmd; /* no need to copy again */
6850 
6851  foreach(child, children)
6852  {
6853  Oid childrelid = lfirst_oid(child);
6854  Relation childrel;
6855  AlteredTableInfo *childtab;
6856 
6857  /* find_inheritance_children already got lock */
6858  childrel = table_open(childrelid, NoLock);
6859  CheckTableNotInUse(childrel, "ALTER TABLE");
6860 
6861  /* Find or create work queue entry for this table */
6862  childtab = ATGetQueueEntry(wqueue, childrel);
6863 
6864  /* Recurse to child; return value is ignored */
6865  ATExecAddColumn(wqueue, childtab, childrel,
6866  &childcmd, recurse, true,
6867  lockmode, cur_pass, context);
6868 
6869  table_close(childrel, NoLock);
6870  }
6871 
6872  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
6873  return address;
6874 }
#define NIL
Definition: pg_list.h:65
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2576
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2485
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:264
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
AttrNumber attnum
Definition: heap.h:29
bool is_local
Definition: parsenodes.h:662
Oid GetUserId(void)
Definition: miscinit.c:478
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
void namestrcpy(Name name, const char *str)
Definition: name.c:233
char identity
Definition: parsenodes.h:668
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:78
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * get_collation_name(Oid colloid)
Definition: lsyscache.c:1060
Expr * expression_planner(Expr *expr)
Definition: planner.c:5653
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
char generated
Definition: parsenodes.h:671
bool is_not_null
Definition: parsenodes.h:663
#define lengthof(array)
Definition: c.h:734
Form_pg_class rd_rel
Definition: rel.h:110
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define ATT_TABLE
Definition: tablecmds.c:306
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3626
signed int int32
Definition: c.h:429
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:337
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1391
#define list_make1(x1)
Definition: pg_list.h:206
RangeVar * identitySequence
Definition: parsenodes.h:669
#define AT_REWRITE_DEFAULT_VAL
Definition: event_trigger.h:33
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
Definition: tablecmds.c:6934
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
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
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:1291
ItemPointerData t_self
Definition: htup.h:65
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:6952
bool missingMode
Definition: heap.h:31
static char GetAttributeCompression(Form_pg_attribute att, char *compression)
Definition: tablecmds.c:18475
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:1042
char generated
Definition: heap.h:32
#define RelationGetRelationName(relation)
Definition: rel.h:491
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5948
Node * raw_default
Definition: heap.h:30
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:203
#define ACL_USAGE
Definition: parsenodes.h:90
void InsertPgAttributeTuples(Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, Datum *attoptions, CatalogIndexState indstate)
Definition: heap.c:740
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3943
bool verify_new_notnull
Definition: tablecmds.c:178
Node * raw_default
Definition: parsenodes.h:666
List * lappend(List *list, void *datum)
Definition: list.c:336
Oid GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid)
Definition: parse_type.c:538
Node * build_column_default(Relation rel, int attrno)
void * palloc0(Size size)
Definition: mcxt.c:1093
AclResult
Definition: acl.h:177
void CommandCounterIncrement(void)
Definition: xact.c:1021
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
#define list_make1_oid(x1)
Definition: pg_list.h:236
static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd **cmd, bool recurse, bool recursing, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:6458
TupleDesc rd_att
Definition: rel.h:111
void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, Oid *typeid_p, int32 *typmod_p)
Definition: parse_type.c:310
FormData_pg_attribute
Definition: pg_attribute.h:187
#define ereport(elevel,...)
Definition: elog.h:157
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3003
#define NOTICE
Definition: elog.h:37
List * find_inheritance_children(Oid parentrelId, bool include_detached, LOCKMODE lockmode)
Definition: pg_inherits.c:60
#define MaxHeapAttributeNumber
Definition: htup_details.h:47
#define makeNode(_type_)
Definition: nodes.h:587
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
static AlterTableCmd * ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5191
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
static int list_length(const List *l)
Definition: pg_list.h:149
bool is_generated
Definition: tablecmds.c:223
#define newval
TypeName * typeName
Definition: parsenodes.h:659
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
#define InvalidCompressionMethod
List * arrayBounds
Definition: parsenodes.h:227
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:6881
#define elog(elevel,...)
Definition: elog.h:232
int inhcount
Definition: parsenodes.h:661
static void ATSimplePermissions(Relation rel, int allowed_targets)
Definition: tablecmds.c:5986
char * colname
Definition: parsenodes.h:658
char * compression
Definition: parsenodes.h:660
#define copyObject(obj)
Definition: nodes.h:655
TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs)
Definition: tupdesc.c:90
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
Definition: heap.c:591
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4811
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:311
#define RelationGetRelid(relation)
Definition: rel.h:457
#define lfirst_oid(lc)
Definition: pg_list.h:171
AttrNumber attnum
Definition: tablecmds.c:220

◆ ATExecAddConstraint()

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

Definition at line 8587 of file tablecmds.c.

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, InvalidOid, IsA, NIL, RelationGetNamespace, RelationGetRelationName, and RelationGetRelid.

Referenced by ATExecCmd().

8590 {
8592 
8593  Assert(IsA(newConstraint, Constraint));
8594 
8595  /*
8596  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
8597  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
8598  * switch anyway to make it easier to add more code later.
8599  */
8600  switch (newConstraint->contype)
8601  {
8602  case CONSTR_CHECK:
8603  address =
8604  ATAddCheckConstraint(wqueue, tab, rel,
8605  newConstraint, recurse, false, is_readd,
8606  lockmode);
8607  break;
8608 
8609  case CONSTR_FOREIGN:
8610 
8611  /*
8612  * Assign or validate constraint name
8613  */
8614  if (newConstraint->conname)
8615  {
8617  RelationGetRelid(rel),
8618  newConstraint->conname))
8619  ereport(ERROR,
8621  errmsg("constraint \"%s\" for relation \"%s\" already exists",
8622  newConstraint->conname,
8623  RelationGetRelationName(rel))));
8624  }
8625  else
8626  newConstraint->conname =
8629  "fkey",
8630  RelationGetNamespace(rel),
8631  NIL);
8632 
8633  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
8634  newConstraint, InvalidOid,
8635  recurse, false,
8636  lockmode);
8637  break;
8638 
8639  default:
8640  elog(ERROR, "unrecognized constraint type: %d",
8641  (int) newConstraint->contype);
8642  }
8643 
8644  return address;
8645 }
#define NIL
Definition: pg_list.h:65
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8660
int errcode(int sqlerrcode)
Definition: elog.c:698
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:8702
char * conname
Definition: parsenodes.h:2233
#define ERROR
Definition: elog.h:46
#define RelationGetRelationName(relation)
Definition: rel.h:491
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, Oid parentConstr, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:8839
ConstrType contype
Definition: parsenodes.h:2230
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
#define RelationGetRelid(relation)
Definition: rel.h:457
List * fk_attrs
Definition: parsenodes.h:2265
#define RelationGetNamespace(relation)
Definition: rel.h:498

◆ ATExecAddIdentity()

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

Definition at line 7451 of file tablecmds.c.

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

Referenced by ATExecCmd().

7453 {
7454  Relation attrelation;
7455  HeapTuple tuple;
7456  Form_pg_attribute attTup;
7458  ObjectAddress address;
7459  ColumnDef *cdef = castNode(ColumnDef, def);
7460 
7461  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7462 
7463  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7464  if (!HeapTupleIsValid(tuple))
7465  ereport(ERROR,
7466  (errcode(ERRCODE_UNDEFINED_COLUMN),
7467  errmsg("column \"%s\" of relation \"%s\" does not exist",
7468  colName, RelationGetRelationName(rel))));
7469  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7470  attnum = attTup->attnum;
7471 
7472  /* Can't alter a system attribute */
7473  if (attnum <= 0)
7474  ereport(ERROR,
7475  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7476  errmsg("cannot alter system column \"%s\"",
7477  colName)));
7478 
7479  /*
7480  * Creating a column as identity implies NOT NULL, so adding the identity
7481  * to an existing column that is not NOT NULL would create a state that
7482  * cannot be reproduced without contortions.
7483  */
7484  if (!attTup->attnotnull)
7485  ereport(ERROR,
7486  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7487  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
7488  colName, RelationGetRelationName(rel))));
7489 
7490  if (attTup->attidentity)
7491  ereport(ERROR,
7492  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7493  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
7494  colName, RelationGetRelationName(rel))));
7495 
7496  if (attTup->atthasdef)
7497  ereport(ERROR,
7498  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7499  errmsg("column \"%s\" of relation \"%s\" already has a default value",
7500  colName, RelationGetRelationName(rel))));
7501 
7502  attTup->attidentity = cdef->identity;
7503  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7504 
7505  InvokeObjectPostAlterHook(RelationRelationId,
7506  RelationGetRelid(rel),
7507  attTup->attnum);
7508  ObjectAddressSubSet(address, RelationRelationId,
7509  RelationGetRelid(rel), attnum);
7510  heap_freetuple(tuple);
7511 
7512  table_close(attrelation, RowExclusiveLock);
7513 
7514  return address;
7515 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
char identity
Definition: parsenodes.h:668
int errcode(int sqlerrcode)
Definition: elog.c:698
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ERROR
Definition: elog.h:46
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:1291
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:491
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:203
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
int16 attnum
Definition: pg_attribute.h:83
#define ereport(elevel,...)
Definition: elog.h:157
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
int errmsg(const char *fmt,...)
Definition: elog.c:909
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:457

◆ ATExecAddIndex()

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

Definition at line 8412 of file tablecmds.c.

References Assert, IndexStmt::concurrent, DefineIndex(), index_close(), index_open(), InvalidOid, IsA, NoLock, ObjectAddress::objectId, OidIsValid, IndexStmt::oldCreateSubid, IndexStmt::oldFirstRelfilenodeSubid, IndexStmt::oldNode, RelationData::rd_createSubid, RelationData::rd_firstRelfilenodeSubid, RelationData::rd_node, RelationGetRelid, RelationPreserveStorage(), AlteredTableInfo::rewrite, and IndexStmt::transformed.

Referenced by ATExecCmd().

8414 {
8415  bool check_rights;
8416  bool skip_build;
8417  bool quiet;
8418  ObjectAddress address;
8419 
8420  Assert(IsA(stmt, IndexStmt));
8421  Assert(!stmt->concurrent);
8422 
8423  /* The IndexStmt has already been through transformIndexStmt */
8424  Assert(stmt->transformed);
8425 
8426  /* suppress schema rights check when rebuilding existing index */
8427  check_rights = !is_rebuild;
8428  /* skip index build if phase 3 will do it or we're reusing an old one */
8429  skip_build = tab->rewrite > 0 || OidIsValid(stmt->oldNode);
8430  /* suppress notices when rebuilding existing index */
8431  quiet = is_rebuild;
8432 
8433  address = DefineIndex(RelationGetRelid(rel),
8434  stmt,
8435  InvalidOid, /* no predefined OID */
8436  InvalidOid, /* no parent index */
8437  InvalidOid, /* no parent constraint */
8438  true, /* is_alter_table */
8439  check_rights,
8440  false, /* check_not_in_use - we did it already */
8441  skip_build,
8442  quiet);
8443 
8444  /*
8445  * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
8446  * index instead of building from scratch. Restore associated fields.
8447  * This may store InvalidSubTransactionId in both fields, in which case
8448  * relcache.c will assume it can rebuild the relcache entry. Hence, do
8449  * this after the CCI that made catalog rows visible to any rebuild. The
8450  * DROP of the old edition of this index will have scheduled the storage
8451  * for deletion at commit, so cancel that pending deletion.
8452  */
8453  if (OidIsValid(stmt->oldNode))
8454  {
8455  Relation irel = index_open(address.objectId, NoLock);
8456 
8457  irel->rd_createSubid = stmt->oldCreateSubid;
8459  RelationPreserveStorage(irel->rd_node, true);
8460  index_close(irel, NoLock);
8461  }
8462 
8463  return address;
8464 }
void RelationPreserveStorage(RelFileNode rnode, bool atCommit)
Definition: storage.c:240
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
ObjectAddress DefineIndex(Oid relationId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition: indexcmds.c:506
SubTransactionId oldCreateSubid
Definition: parsenodes.h:2868
#define OidIsValid(objectId)
Definition: c.h:710
#define NoLock
Definition: lockdefs.h:34
bool transformed
Definition: parsenodes.h:2876
SubTransactionId oldFirstRelfilenodeSubid
Definition: parsenodes.h:2869
SubTransactionId rd_createSubid
Definition: rel.h:103
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:106
#define InvalidOid
Definition: postgres_ext.h:36
RelFileNode rd_node
Definition: rel.h:55
#define Assert(condition)
Definition: c.h:804
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
bool concurrent
Definition: parsenodes.h:2877
#define RelationGetRelid(relation)
Definition: rel.h:457
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132

◆ ATExecAddIndexConstraint()

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

Definition at line 8495 of file tablecmds.c.

References AccessShareLock, allowSystemTableMods, Assert, BuildIndexInfo(), IndexStmt::deferrable, elog, ereport, errcode(), errmsg(), ERROR, IndexStmt::idxname, 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(), IndexStmt::indexOid, IndexStmt::initdeferred, InvalidOid, IsA, IndexStmt::isconstraint, NoLock, NOTICE, OidIsValid, IndexStmt::primary, pstrdup(), RelationData::rd_rel, RelationGetRelationName, and RenameRelationInternal().

Referenced by ATExecCmd().

8497 {
8498  Oid index_oid = stmt->indexOid;
8499  Relation indexRel;
8500  char *indexName;
8501  IndexInfo *indexInfo;
8502  char *constraintName;
8503  char constraintType;
8504  ObjectAddress address;
8505  bits16 flags;
8506 
8507  Assert(IsA(stmt, IndexStmt));
8508  Assert(OidIsValid(index_oid));
8509  Assert(stmt->isconstraint);
8510 
8511  /*
8512  * Doing this on partitioned tables is not a simple feature to implement,
8513  * so let's punt for now.
8514  */
8515  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8516  ereport(ERROR,
8517  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8518  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
8519 
8520  indexRel = index_open(index_oid, AccessShareLock);
8521 
8522  indexName = pstrdup(RelationGetRelationName(indexRel));
8523 
8524  indexInfo = BuildIndexInfo(indexRel);
8525 
8526  /* this should have been checked at parse time */
8527  if (!indexInfo->ii_Unique)
8528  elog(ERROR, "index \"%s\" is not unique", indexName);
8529 
8530  /*
8531  * Determine name to assign to constraint. We require a constraint to
8532  * have the same name as the underlying index; therefore, use the index's
8533  * existing name as the default constraint name, and if the user
8534  * explicitly gives some other name for the constraint, rename the index
8535  * to match.
8536  */
8537  constraintName = stmt->idxname;
8538  if (constraintName == NULL)
8539  constraintName = indexName;
8540  else if (strcmp(constraintName, indexName) != 0)
8541  {
8542  ereport(NOTICE,
8543  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
8544  indexName, constraintName)));
8545  RenameRelationInternal(index_oid, constraintName, false, true);
8546  }
8547 
8548  /* Extra checks needed if making primary key */
8549&