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

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Functions

static void truncate_check_rel (Oid relid, Form_pg_class reltuple)
 
static void truncate_check_perms (Oid relid, Form_pg_class reltuple)
 
static void truncate_check_activity (Relation rel)
 
static void RangeVarCallbackForTruncate (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
static ListMergeAttributes (List *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 bool ATExecAlterConstrRecurse (Constraint *cmdcon, Relation conrel, Relation tgrel, Relation rel, HeapTuple contuple, List **otherrelids, LOCKMODE lockmode)
 
static ObjectAddress ATExecValidateConstraint (List **wqueue, Relation rel, char *constrName, bool recurse, bool recursing, LOCKMODE lockmode)
 
static int transformColumnNameList (Oid relId, List *colList, int16 *attnums, Oid *atttypids)
 
static int transformFkeyGetPrimaryKey (Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
 
static Oid transformFkeyCheckAttrs (Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
 
static void checkFkeyPermissions (Relation rel, int16 *attnums, int natts)
 
static CoercionPathType findFkeyCast (Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
 
static void validateForeignKeyConstraint (char *conname, Relation rel, Relation pkrel, Oid pkindOid, Oid constraintOid)
 
static void ATController (AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATPrepCmd (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATRewriteCatalogs (List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATExecCmd (List **wqueue, AlteredTableInfo *tab, AlterTableCmd *cmd, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
 
static AlterTableCmdATParseTransformCmd (List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
 
static void ATRewriteTables (AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATRewriteTable (AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 
static AlteredTableInfoATGetQueueEntry (List **wqueue, Relation rel)
 
static void ATSimplePermissions (AlterTableType cmdtype, Relation rel, int allowed_targets)
 
static void ATSimpleRecursion (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static void ATCheckPartitionsNotInUse (Relation rel, LOCKMODE lockmode)
 
static void ATTypedTableRecursion (List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static Listfind_typed_table_dependencies (Oid typeOid, const char *typeName, DropBehavior behavior)
 
static void ATPrepAddColumn (List **wqueue, Relation rel, bool recurse, bool recursing, bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static ObjectAddress ATExecAddColumn (List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd **cmd, bool recurse, bool recursing, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
 
static bool check_for_column_name_collision (Relation rel, const char *colname, bool if_not_exists)
 
static void add_column_datatype_dependency (Oid relid, int32 attnum, Oid typid)
 
static void add_column_collation_dependency (Oid relid, int32 attnum, Oid collid)
 
static 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, bool recurse, bool recursing, LOCKMODE lockmode)
 
static ObjectAddress addFkRecurseReferenced (List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, Oid parentDelTrigger, Oid parentUpdTrigger)
 
static void validateFkOnDeleteSetColumns (int numfks, const int16 *fkattnums, int numfksetcols, const int16 *fksetcolsattnums, List *fksetcols)
 
static void addFkRecurseReferencing (List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, LOCKMODE lockmode, Oid parentInsTrigger, Oid parentUpdTrigger)
 
static void CloneForeignKeyConstraints (List **wqueue, Relation parentRel, Relation partitionRel)
 
static void CloneFkReferenced (Relation parentRel, Relation partitionRel)
 
static void CloneFkReferencing (List **wqueue, Relation parentRel, Relation partRel)
 
static void createForeignKeyCheckTriggers (Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
 
static void createForeignKeyActionTriggers (Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
 
static bool tryAttachPartitionForeignKey (ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop, Oid parentInsTrigger, Oid parentUpdTrigger, Relation trigrel)
 
static void GetForeignKeyActionTriggers (Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *deleteTriggerOid, Oid *updateTriggerOid)
 
static void GetForeignKeyCheckTriggers (Relation trigrel, Oid conoid, Oid confrelid, Oid conrelid, Oid *insertTriggerOid, Oid *updateTriggerOid)
 
static void ATExecDropConstraint (Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode)
 
static void ATPrepAlterColumnType (List **wqueue, AlteredTableInfo *tab, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static bool ATColumnChangeRequiresRewrite (Node *expr, AttrNumber varattno)
 
static ObjectAddress ATExecAlterColumnType (AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static void RememberConstraintForRebuilding (Oid conoid, AlteredTableInfo *tab)
 
static void RememberIndexForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
static void RememberStatisticsForRebuilding (Oid stxoid, AlteredTableInfo *tab)
 
static void ATPostAlterTypeCleanup (List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
 
static void ATPostAlterTypeParse (Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, List **wqueue, LOCKMODE lockmode, bool rewrite)
 
static void RebuildConstraintComment (AlteredTableInfo *tab, int pass, Oid objid, Relation rel, List *domname, const char *conname)
 
static void TryReuseIndex (Oid oldId, IndexStmt *stmt)
 
static void TryReuseForeignKey (Oid oldId, Constraint *con)
 
static ObjectAddress ATExecAlterColumnGenericOptions (Relation rel, const char *colName, List *options, LOCKMODE lockmode)
 
static void change_owner_fix_column_acls (Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
 
static void change_owner_recurse_to_sequences (Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
 
static ObjectAddress ATExecClusterOn (Relation rel, const char *indexName, LOCKMODE lockmode)
 
static void ATExecDropCluster (Relation rel, LOCKMODE lockmode)
 
static void ATPrepSetAccessMethod (AlteredTableInfo *tab, Relation rel, const char *amname)
 
static bool ATPrepChangePersistence (Relation rel, bool toLogged)
 
static void ATPrepSetTableSpace (AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
 
static void ATExecSetTableSpace (Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 
static void ATExecSetTableSpaceNoStorage (Relation rel, Oid newTableSpace)
 
static void ATExecSetRelOptions (Relation rel, List *defList, AlterTableType operation, LOCKMODE lockmode)
 
static void ATExecEnableDisableTrigger (Relation rel, const char *trigname, char fires_when, bool skip_system, bool recurse, LOCKMODE lockmode)
 
static void ATExecEnableDisableRule (Relation rel, const char *rulename, char fires_when, LOCKMODE lockmode)
 
static void ATPrepAddInherit (Relation child_rel)
 
static ObjectAddress ATExecAddInherit (Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
 
static ObjectAddress ATExecDropInherit (Relation rel, RangeVar *parent, LOCKMODE lockmode)
 
static void drop_parent_dependency (Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
 
static ObjectAddress ATExecAddOf (Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
 
static void ATExecDropOf (Relation rel, LOCKMODE lockmode)
 
static void ATExecReplicaIdentity (Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
 
static void ATExecGenericOptions (Relation rel, List *options)
 
static void ATExecSetRowSecurity (Relation rel, bool rls)
 
static void ATExecForceNoForceRowSecurity (Relation rel, bool force_rls)
 
static ObjectAddress ATExecSetCompression (Relation rel, const char *column, Node *newValue, LOCKMODE lockmode)
 
static void index_copy_data (Relation rel, RelFileLocator newrlocator)
 
static const char * storage_name (char c)
 
static void RangeVarCallbackForDropRelation (const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
 
static void RangeVarCallbackForAlterRelation (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
static PartitionSpectransformPartitionSpec (Relation rel, PartitionSpec *partspec)
 
static void ComputePartitionAttrs (ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, PartitionStrategy strategy)
 
static void CreateInheritance (Relation child_rel, Relation parent_rel)
 
static void RemoveInheritance (Relation child_rel, Relation parent_rel, bool expect_detached)
 
static 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 parentIdx, RangeVar *name)
 
static void validatePartitionedIndex (Relation partedIdx, Relation partedTbl)
 
static void refuseDupeIndexAttach (Relation parentIdx, Relation partIdx, Relation partitionTbl)
 
static ListGetParentedForeignKeyRefs (Relation partition)
 
static void ATDetachCheckNoForeignKeyRefs (Relation partition)
 
static char GetAttributeCompression (Oid atttypid, char *compression)
 
static char GetAttributeStorage (Oid atttypid, const char *storagemode)
 
ObjectAddress DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
 
static void DropErrorMsgNonExistent (RangeVar *rel, char rightkind, bool missing_ok)
 
static void DropErrorMsgWrongType (const char *relname, char wrongkind, char rightkind)
 
void RemoveRelations (DropStmt *drop)
 
void ExecuteTruncate (TruncateStmt *stmt)
 
void ExecuteTruncateGuts (List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs)
 
void SetRelationHasSubclass (Oid relationId, bool relhassubclass)
 
bool CheckRelationTableSpaceMove (Relation rel, Oid newTableSpaceId)
 
void SetRelationTableSpace (Relation rel, Oid newTableSpaceId, RelFileNumber newRelFilenumber)
 
static void renameatt_check (Oid myrelid, Form_pg_class classform, bool recursing)
 
static AttrNumber renameatt_internal (Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
 
static void RangeVarCallbackForRenameAttribute (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
ObjectAddress renameatt (RenameStmt *stmt)
 
static ObjectAddress rename_constraint_internal (Oid myrelid, Oid mytypid, const char *oldconname, const char *newconname, bool recurse, bool recursing, int expected_parents)
 
ObjectAddress RenameConstraint (RenameStmt *stmt)
 
ObjectAddress RenameRelation (RenameStmt *stmt)
 
void RenameRelationInternal (Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
 
void ResetRelRewrite (Oid myrelid)
 
void CheckTableNotInUse (Relation rel, const char *stmt)
 
Oid AlterTableLookupRelation (AlterTableStmt *stmt, LOCKMODE lockmode)
 
void AlterTable (AlterTableStmt *stmt, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
void AlterTableInternal (Oid relid, List *cmds, bool recurse)
 
LOCKMODE AlterTableGetLockLevel (List *cmds)
 
static const char * alter_table_type_to_string (AlterTableType cmdtype)
 
void find_composite_type_dependencies (Oid typeOid, Relation origRelation, const char *origTypeName)
 
void check_of_type (HeapTuple typetuple)
 
static void SetIndexStorageProperties (Relation rel, Relation attrelation, AttrNumber attnum, bool setstorage, char newstorage, bool setcompression, char newcompression, LOCKMODE lockmode)
 
static Oid CreateFKCheckTrigger (Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentTrigOid, bool on_insert)
 
static void RememberReplicaIdentityForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
static void RememberClusterOnForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
void ATExecChangeOwner (Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
 
Oid AlterTableMoveAll (AlterTableMoveAllStmt *stmt)
 
static char * decompile_conbin (HeapTuple contup, TupleDesc tupdesc)
 
static bool constraints_equivalent (HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
 
static void MarkInheritDetached (Relation child_rel, Relation parent_rel)
 
static void relation_mark_replica_identity (Relation rel, char ri_type, Oid indexOid, bool is_internal)
 
ObjectAddress AlterTableNamespace (AlterObjectSchemaStmt *stmt, Oid *oldschema)
 
void AlterTableNamespaceInternal (Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
 
void AlterRelationNamespaceInternal (Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
 
void register_on_commit_action (Oid relid, OnCommitAction action)
 
void remove_on_commit_action (Oid relid)
 
void PreCommit_on_commit_actions (void)
 
void AtEOXact_on_commit_actions (bool isCommit)
 
void AtEOSubXact_on_commit_actions (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
void RangeVarCallbackOwnsTable (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
void RangeVarCallbackOwnsRelation (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
bool PartConstraintImpliedByRelConstraint (Relation scanrel, List *partConstraint)
 
static void RangeVarCallbackForAttachIndex (const RangeVar *rv, Oid relOid, Oid oldRelOid, void *arg)
 

Variables

static Liston_commits = NIL
 
static const struct dropmsgstrings dropmsgstringarray []
 

Macro Definition Documentation

◆ AT_NUM_PASSES

#define AT_NUM_PASSES   11

Definition at line 156 of file tablecmds.c.

◆ AT_PASS_ADD_COL

#define AT_PASS_ADD_COL   4 /* ADD COLUMN */

Definition at line 149 of file tablecmds.c.

◆ AT_PASS_ADD_CONSTR

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

Definition at line 150 of file tablecmds.c.

◆ AT_PASS_ADD_INDEX

#define AT_PASS_ADD_INDEX   8 /* ADD indexes */

Definition at line 153 of file tablecmds.c.

◆ AT_PASS_ADD_INDEXCONSTR

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

Definition at line 152 of file tablecmds.c.

◆ AT_PASS_ADD_OTHERCONSTR

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

Definition at line 154 of file tablecmds.c.

◆ AT_PASS_ALTER_TYPE

#define AT_PASS_ALTER_TYPE   1 /* ALTER COLUMN TYPE */

Definition at line 145 of file tablecmds.c.

◆ AT_PASS_COL_ATTRS

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

Definition at line 151 of file tablecmds.c.

◆ AT_PASS_DROP

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

Definition at line 144 of file tablecmds.c.

◆ AT_PASS_MISC

#define AT_PASS_MISC   10 /* other stuff */

Definition at line 155 of file tablecmds.c.

◆ AT_PASS_OLD_CONSTR

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

Definition at line 147 of file tablecmds.c.

◆ AT_PASS_OLD_INDEX

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

Definition at line 146 of file tablecmds.c.

◆ AT_PASS_UNSET

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

Definition at line 143 of file tablecmds.c.

◆ ATT_COMPOSITE_TYPE

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 319 of file tablecmds.c.

◆ ATT_FOREIGN_TABLE

#define ATT_FOREIGN_TABLE   0x0020

Definition at line 320 of file tablecmds.c.

◆ ATT_INDEX

#define ATT_INDEX   0x0008

Definition at line 318 of file tablecmds.c.

◆ ATT_MATVIEW

#define ATT_MATVIEW   0x0004

Definition at line 317 of file tablecmds.c.

◆ ATT_PARTITIONED_INDEX

#define ATT_PARTITIONED_INDEX   0x0040

Definition at line 321 of file tablecmds.c.

◆ ATT_SEQUENCE

#define ATT_SEQUENCE   0x0080

Definition at line 322 of file tablecmds.c.

◆ ATT_TABLE

#define ATT_TABLE   0x0001

Definition at line 315 of file tablecmds.c.

◆ ATT_VIEW

#define ATT_VIEW   0x0002

Definition at line 316 of file tablecmds.c.

◆ child_dependency_type

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

Definition at line 343 of file tablecmds.c.

Typedef Documentation

◆ AlteredTableInfo

◆ ForeignTruncateInfo

◆ NewColumnValue

◆ NewConstraint

typedef struct NewConstraint NewConstraint

◆ OnCommitItem

typedef struct OnCommitItem OnCommitItem

Function Documentation

◆ add_column_collation_dependency()

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

Definition at line 7174 of file tablecmds.c.

7175 {
7176  ObjectAddress myself,
7177  referenced;
7178 
7179  /* We know the default collation is pinned, so don't bother recording it */
7180  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7181  {
7182  myself.classId = RelationRelationId;
7183  myself.objectId = relid;
7184  myself.objectSubId = attnum;
7185  referenced.classId = CollationRelationId;
7186  referenced.objectId = collid;
7187  referenced.objectSubId = 0;
7188  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7189  }
7190 }
#define OidIsValid(objectId)
Definition: c.h:711
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int16 attnum
Definition: pg_attribute.h:83
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

◆ add_column_datatype_dependency()

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

Definition at line 7156 of file tablecmds.c.

7157 {
7158  ObjectAddress myself,
7159  referenced;
7160 
7161  myself.classId = RelationRelationId;
7162  myself.objectId = relid;
7163  myself.objectSubId = attnum;
7164  referenced.classId = TypeRelationId;
7165  referenced.objectId = typid;
7166  referenced.objectSubId = 0;
7167  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7168 }

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

◆ addFkRecurseReferenced()

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

Definition at line 9505 of file tablecmds.c.

9513 {
9514  ObjectAddress address;
9515  Oid constrOid;
9516  char *conname;
9517  bool conislocal;
9518  int coninhcount;
9519  bool connoinherit;
9520  Oid deleteTriggerOid,
9521  updateTriggerOid;
9522 
9523  /*
9524  * Verify relkind for each referenced partition. At the top level, this
9525  * is redundant with a previous check, but we need it when recursing.
9526  */
9527  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9528  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9529  ereport(ERROR,
9530  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9531  errmsg("referenced relation \"%s\" is not a table",
9532  RelationGetRelationName(pkrel))));
9533 
9534  /*
9535  * Caller supplies us with a constraint name; however, it may be used in
9536  * this partition, so come up with a different one in that case.
9537  */
9539  RelationGetRelid(rel),
9540  fkconstraint->conname))
9543  "fkey",
9544  RelationGetNamespace(rel), NIL);
9545  else
9546  conname = fkconstraint->conname;
9547 
9548  if (OidIsValid(parentConstr))
9549  {
9550  conislocal = false;
9551  coninhcount = 1;
9552  connoinherit = false;
9553  }
9554  else
9555  {
9556  conislocal = true;
9557  coninhcount = 0;
9558 
9559  /*
9560  * always inherit for partitioned tables, never for legacy inheritance
9561  */
9562  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
9563  }
9564 
9565  /*
9566  * Record the FK constraint in pg_constraint.
9567  */
9568  constrOid = CreateConstraintEntry(conname,
9569  RelationGetNamespace(rel),
9570  CONSTRAINT_FOREIGN,
9571  fkconstraint->deferrable,
9572  fkconstraint->initdeferred,
9573  fkconstraint->initially_valid,
9574  parentConstr,
9575  RelationGetRelid(rel),
9576  fkattnum,
9577  numfks,
9578  numfks,
9579  InvalidOid, /* not a domain constraint */
9580  indexOid,
9581  RelationGetRelid(pkrel),
9582  pkattnum,
9583  pfeqoperators,
9584  ppeqoperators,
9585  ffeqoperators,
9586  numfks,
9587  fkconstraint->fk_upd_action,
9588  fkconstraint->fk_del_action,
9589  fkdelsetcols,
9590  numfkdelsetcols,
9591  fkconstraint->fk_matchtype,
9592  NULL, /* no exclusion constraint */
9593  NULL, /* no check constraint */
9594  NULL,
9595  conislocal, /* islocal */
9596  coninhcount, /* inhcount */
9597  connoinherit, /* conNoInherit */
9598  false); /* is_internal */
9599 
9600  ObjectAddressSet(address, ConstraintRelationId, constrOid);
9601 
9602  /*
9603  * Mark the child constraint as part of the parent constraint; it must not
9604  * be dropped on its own. (This constraint is deleted when the partition
9605  * is detached, but a special check needs to occur that the partition
9606  * contains no referenced values.)
9607  */
9608  if (OidIsValid(parentConstr))
9609  {
9610  ObjectAddress referenced;
9611 
9612  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9613  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
9614  }
9615 
9616  /* make new constraint visible, in case we add more */
9618 
9619  /*
9620  * Create the action triggers that enforce the constraint.
9621  */
9623  fkconstraint,
9624  constrOid, indexOid,
9625  parentDelTrigger, parentUpdTrigger,
9626  &deleteTriggerOid, &updateTriggerOid);
9627 
9628  /*
9629  * If the referenced table is partitioned, recurse on ourselves to handle
9630  * each partition. We need one pg_constraint row created for each
9631  * partition in addition to the pg_constraint row for the parent table.
9632  */
9633  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9634  {
9635  PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
9636 
9637  for (int i = 0; i < pd->nparts; i++)
9638  {
9639  Relation partRel;
9640  AttrMap *map;
9641  AttrNumber *mapped_pkattnum;
9642  Oid partIndexId;
9643 
9644  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
9645 
9646  /*
9647  * Map the attribute numbers in the referenced side of the FK
9648  * definition to match the partition's column layout.
9649  */
9651  RelationGetDescr(pkrel),
9652  false);
9653  if (map)
9654  {
9655  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
9656  for (int j = 0; j < numfks; j++)
9657  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
9658  }
9659  else
9660  mapped_pkattnum = pkattnum;
9661 
9662  /* do the deed */
9663  partIndexId = index_get_partition(partRel, indexOid);
9664  if (!OidIsValid(partIndexId))
9665  elog(ERROR, "index for %u not found in partition %s",
9666  indexOid, RelationGetRelationName(partRel));
9667  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
9668  partIndexId, constrOid, numfks,
9669  mapped_pkattnum, fkattnum,
9670  pfeqoperators, ppeqoperators, ffeqoperators,
9671  numfkdelsetcols, fkdelsetcols,
9672  old_check_ok,
9673  deleteTriggerOid, updateTriggerOid);
9674 
9675  /* Done -- clean up (but keep the lock) */
9676  table_close(partRel, NoLock);
9677  if (map)
9678  {
9679  pfree(mapped_pkattnum);
9680  free_attrmap(map);
9681  }
9682  }
9683  }
9684 
9685  return address;
9686 }
void free_attrmap(AttrMap *map)
Definition: attmap.c:57
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:264
int16 AttrNumber
Definition: attnum.h:21
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int errcode(int sqlerrcode)
Definition: elog.c:695
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define ERROR
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:145
int j
Definition: isn.c:74
int i
Definition: isn.c:73
#define NoLock
Definition: lockdefs.h:34
#define ShareRowExclusiveLock
Definition: lockdefs.h:41
void pfree(void *pointer)
Definition: mcxt.c:1306
void * palloc(Size size)
Definition: mcxt.c:1199
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:72
Oid index_get_partition(Relation partition, Oid indexId)
Definition: partition.c:175
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:50
@ CONSTRAINT_RELATION
#define NIL
Definition: pg_list.h:66
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetRelid(relation)
Definition: rel.h:501
#define RelationGetDescr(relation)
Definition: rel.h:527
#define RelationGetRelationName(relation)
Definition: rel.h:535
#define RelationGetNamespace(relation)
Definition: rel.h:542
Definition: attmap.h:35
AttrNumber * attnums
Definition: attmap.h:36
bool initdeferred
Definition: parsenodes.h:2346
char fk_upd_action
Definition: parsenodes.h:2380
char fk_matchtype
Definition: parsenodes.h:2379
bool initially_valid
Definition: parsenodes.h:2389
bool deferrable
Definition: parsenodes.h:2345
char * conname
Definition: parsenodes.h:2344
char fk_del_action
Definition: parsenodes.h:2381
List * fk_attrs
Definition: parsenodes.h:2377
Form_pg_class rd_rel
Definition: rel.h:110
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8839
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:11698
static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, Oid parentDelTrigger, Oid parentUpdTrigger)
Definition: tablecmds.c:9505
void CommandCounterIncrement(void)
Definition: xact.c:1077

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

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferenced().

◆ addFkRecurseReferencing()

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

Definition at line 9725 of file tablecmds.c.

9732 {
9733  Oid insertTriggerOid,
9734  updateTriggerOid;
9735 
9736  Assert(OidIsValid(parentConstr));
9737 
9738  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
9739  ereport(ERROR,
9740  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9741  errmsg("foreign key constraints are not supported on foreign tables")));
9742 
9743  /*
9744  * Add the check triggers to it and, if necessary, schedule it to be
9745  * checked in Phase 3.
9746  *
9747  * If the relation is partitioned, drill down to do it to its partitions.
9748  */
9750  RelationGetRelid(pkrel),
9751  fkconstraint,
9752  parentConstr,
9753  indexOid,
9754  parentInsTrigger, parentUpdTrigger,
9755  &insertTriggerOid, &updateTriggerOid);
9756 
9757  if (rel->rd_rel->relkind == RELKIND_RELATION)
9758  {
9759  /*
9760  * Tell Phase 3 to check that the constraint is satisfied by existing
9761  * rows. We can skip this during table creation, when requested
9762  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
9763  * and when we're recreating a constraint following a SET DATA TYPE
9764  * operation that did not impugn its validity.
9765  */
9766  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
9767  {
9768  NewConstraint *newcon;
9769  AlteredTableInfo *tab;
9770 
9771  tab = ATGetQueueEntry(wqueue, rel);
9772 
9773  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9774  newcon->name = get_constraint_name(parentConstr);
9775  newcon->contype = CONSTR_FOREIGN;
9776  newcon->refrelid = RelationGetRelid(pkrel);
9777  newcon->refindid = indexOid;
9778  newcon->conid = parentConstr;
9779  newcon->qual = (Node *) fkconstraint;
9780 
9781  tab->constraints = lappend(tab->constraints, newcon);
9782  }
9783  }
9784  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9785  {
9786  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
9787  Relation trigrel;
9788 
9789  /*
9790  * Triggers of the foreign keys will be manipulated a bunch of times
9791  * in the loop below. To avoid repeatedly opening/closing the trigger
9792  * catalog relation, we open it here and pass it to the subroutines
9793  * called below.
9794  */
9795  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
9796 
9797  /*
9798  * Recurse to take appropriate action on each partition; either we
9799  * find an existing constraint to reparent to ours, or we create a new
9800  * one.
9801  */
9802  for (int i = 0; i < pd->nparts; i++)
9803  {
9804  Oid partitionId = pd->oids[i];
9805  Relation partition = table_open(partitionId, lockmode);
9806  List *partFKs;
9807  AttrMap *attmap;
9808  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
9809  bool attached;
9810  char *conname;
9811  Oid constrOid;
9812  ObjectAddress address,
9813  referenced;
9814  ListCell *cell;
9815 
9816  CheckTableNotInUse(partition, "ALTER TABLE");
9817 
9818  attmap = build_attrmap_by_name(RelationGetDescr(partition),
9819  RelationGetDescr(rel),
9820  false);
9821  for (int j = 0; j < numfks; j++)
9822  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
9823 
9824  /* Check whether an existing constraint can be repurposed */
9825  partFKs = copyObject(RelationGetFKeyList(partition));
9826  attached = false;
9827  foreach(cell, partFKs)
9828  {
9829  ForeignKeyCacheInfo *fk;
9830 
9831  fk = lfirst_node(ForeignKeyCacheInfo, cell);
9833  partitionId,
9834  parentConstr,
9835  numfks,
9836  mapped_fkattnum,
9837  pkattnum,
9838  pfeqoperators,
9839  insertTriggerOid,
9840  updateTriggerOid,
9841  trigrel))
9842  {
9843  attached = true;
9844  break;
9845  }
9846  }
9847  if (attached)
9848  {
9849  table_close(partition, NoLock);
9850  continue;
9851  }
9852 
9853  /*
9854  * No luck finding a good constraint to reuse; create our own.
9855  */
9857  RelationGetRelid(partition),
9858  fkconstraint->conname))
9859  conname = ChooseConstraintName(RelationGetRelationName(partition),
9861  "fkey",
9862  RelationGetNamespace(partition), NIL);
9863  else
9864  conname = fkconstraint->conname;
9865  constrOid =
9866  CreateConstraintEntry(conname,
9867  RelationGetNamespace(partition),
9868  CONSTRAINT_FOREIGN,
9869  fkconstraint->deferrable,
9870  fkconstraint->initdeferred,
9871  fkconstraint->initially_valid,
9872  parentConstr,
9873  partitionId,
9874  mapped_fkattnum,
9875  numfks,
9876  numfks,
9877  InvalidOid,
9878  indexOid,
9879  RelationGetRelid(pkrel),
9880  pkattnum,
9881  pfeqoperators,
9882  ppeqoperators,
9883  ffeqoperators,
9884  numfks,
9885  fkconstraint->fk_upd_action,
9886  fkconstraint->fk_del_action,
9887  fkdelsetcols,
9888  numfkdelsetcols,
9889  fkconstraint->fk_matchtype,
9890  NULL,
9891  NULL,
9892  NULL,
9893  false,
9894  1,
9895  false,
9896  false);
9897 
9898  /*
9899  * Give this constraint partition-type dependencies on the parent
9900  * constraint as well as the table.
9901  */
9902  ObjectAddressSet(address, ConstraintRelationId, constrOid);
9903  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9904  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
9905  ObjectAddressSet(referenced, RelationRelationId, partitionId);
9906  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
9907 
9908  /* Make all this visible before recursing */
9910 
9911  /* call ourselves to finalize the creation and we're done */
9912  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
9913  indexOid,
9914  constrOid,
9915  numfks,
9916  pkattnum,
9917  mapped_fkattnum,
9918  pfeqoperators,
9919  ppeqoperators,
9920  ffeqoperators,
9921  numfkdelsetcols,
9922  fkdelsetcols,
9923  old_check_ok,
9924  lockmode,
9925  insertTriggerOid,
9926  updateTriggerOid);
9927 
9928  table_close(partition, NoLock);
9929  }
9930 
9931  table_close(trigrel, RowExclusiveLock);
9932  }
9933 }
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:178
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1107
void * palloc0(Size size)
Definition: mcxt.c:1230
#define copyObject(obj)
Definition: nodes.h:233
@ CONSTR_FOREIGN
Definition: parsenodes.h:2317
#define INDEX_MAX_KEYS
#define lfirst_node(type, lc)
Definition: pg_list.h:174
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4629
List * constraints
Definition: tablecmds.c:177
bool skip_validation
Definition: parsenodes.h:2388
Definition: pg_list.h:52
char * name
Definition: tablecmds.c:204
ConstrType contype
Definition: tablecmds.c:205
Node * qual
Definition: tablecmds.c:209
Definition: nodes.h:118
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:6075
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:4004
static bool tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop, Oid parentInsTrigger, Oid parentUpdTrigger, Relation trigrel)
Definition: tablecmds.c:10453
static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, int numfkdelsetcols, int16 *fkdelsetcols, bool old_check_ok, LOCKMODE lockmode, Oid parentInsTrigger, Oid parentUpdTrigger)
Definition: tablecmds.c:9725
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:11833

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

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferencing().

◆ alter_table_type_to_string()

static const char* alter_table_type_to_string ( AlterTableType  cmdtype)
static

Definition at line 6108 of file tablecmds.c.

6109 {
6110  switch (cmdtype)
6111  {
6112  case AT_AddColumn:
6113  case AT_AddColumnRecurse:
6114  case AT_AddColumnToView:
6115  return "ADD COLUMN";
6116  case AT_ColumnDefault:
6118  return "ALTER COLUMN ... SET DEFAULT";
6119  case AT_DropNotNull:
6120  return "ALTER COLUMN ... DROP NOT NULL";
6121  case AT_SetNotNull:
6122  return "ALTER COLUMN ... SET NOT NULL";
6123  case AT_DropExpression:
6124  return "ALTER COLUMN ... DROP EXPRESSION";
6125  case AT_CheckNotNull:
6126  return NULL; /* not real grammar */
6127  case AT_SetStatistics:
6128  return "ALTER COLUMN ... SET STATISTICS";
6129  case AT_SetOptions:
6130  return "ALTER COLUMN ... SET";
6131  case AT_ResetOptions:
6132  return "ALTER COLUMN ... RESET";
6133  case AT_SetStorage:
6134  return "ALTER COLUMN ... SET STORAGE";
6135  case AT_SetCompression:
6136  return "ALTER COLUMN ... SET COMPRESSION";
6137  case AT_DropColumn:
6138  case AT_DropColumnRecurse:
6139  return "DROP COLUMN";
6140  case AT_AddIndex:
6141  case AT_ReAddIndex:
6142  return NULL; /* not real grammar */
6143  case AT_AddConstraint:
6145  case AT_ReAddConstraint:
6147  case AT_AddIndexConstraint:
6148  return "ADD CONSTRAINT";
6149  case AT_AlterConstraint:
6150  return "ALTER CONSTRAINT";
6151  case AT_ValidateConstraint:
6153  return "VALIDATE CONSTRAINT";
6154  case AT_DropConstraint:
6156  return "DROP CONSTRAINT";
6157  case AT_ReAddComment:
6158  return NULL; /* not real grammar */
6159  case AT_AlterColumnType:
6160  return "ALTER COLUMN ... SET DATA TYPE";
6162  return "ALTER COLUMN ... OPTIONS";
6163  case AT_ChangeOwner:
6164  return "OWNER TO";
6165  case AT_ClusterOn:
6166  return "CLUSTER ON";
6167  case AT_DropCluster:
6168  return "SET WITHOUT CLUSTER";
6169  case AT_SetAccessMethod:
6170  return "SET ACCESS METHOD";
6171  case AT_SetLogged:
6172  return "SET LOGGED";
6173  case AT_SetUnLogged:
6174  return "SET UNLOGGED";
6175  case AT_DropOids:
6176  return "SET WITHOUT OIDS";
6177  case AT_SetTableSpace:
6178  return "SET TABLESPACE";
6179  case AT_SetRelOptions:
6180  return "SET";
6181  case AT_ResetRelOptions:
6182  return "RESET";
6183  case AT_ReplaceRelOptions:
6184  return NULL; /* not real grammar */
6185  case AT_EnableTrig:
6186  return "ENABLE TRIGGER";
6187  case AT_EnableAlwaysTrig:
6188  return "ENABLE ALWAYS TRIGGER";
6189  case AT_EnableReplicaTrig:
6190  return "ENABLE REPLICA TRIGGER";
6191  case AT_DisableTrig:
6192  return "DISABLE TRIGGER";
6193  case AT_EnableTrigAll:
6194  return "ENABLE TRIGGER ALL";
6195  case AT_DisableTrigAll:
6196  return "DISABLE TRIGGER ALL";
6197  case AT_EnableTrigUser:
6198  return "ENABLE TRIGGER USER";
6199  case AT_DisableTrigUser:
6200  return "DISABLE TRIGGER USER";
6201  case AT_EnableRule:
6202  return "ENABLE RULE";
6203  case AT_EnableAlwaysRule:
6204  return "ENABLE ALWAYS RULE";
6205  case AT_EnableReplicaRule:
6206  return "ENABLE REPLICA RULE";
6207  case AT_DisableRule:
6208  return "DISABLE RULE";
6209  case AT_AddInherit:
6210  return "INHERIT";
6211  case AT_DropInherit:
6212  return "NO INHERIT";
6213  case AT_AddOf:
6214  return "OF";
6215  case AT_DropOf:
6216  return "NOT OF";
6217  case AT_ReplicaIdentity:
6218  return "REPLICA IDENTITY";
6219  case AT_EnableRowSecurity:
6220  return "ENABLE ROW SECURITY";
6221  case AT_DisableRowSecurity:
6222  return "DISABLE ROW SECURITY";
6223  case AT_ForceRowSecurity:
6224  return "FORCE ROW SECURITY";
6225  case AT_NoForceRowSecurity:
6226  return "NO FORCE ROW SECURITY";
6227  case AT_GenericOptions:
6228  return "OPTIONS";
6229  case AT_AttachPartition:
6230  return "ATTACH PARTITION";
6231  case AT_DetachPartition:
6232  return "DETACH PARTITION";
6234  return "DETACH PARTITION ... FINALIZE";
6235  case AT_AddIdentity:
6236  return "ALTER COLUMN ... ADD IDENTITY";
6237  case AT_SetIdentity:
6238  return "ALTER COLUMN ... SET";
6239  case AT_DropIdentity:
6240  return "ALTER COLUMN ... DROP IDENTITY";
6241  case AT_ReAddStatistics:
6242  return NULL; /* not real grammar */
6243  }
6244 
6245  return NULL;
6246 }
@ AT_AddIndexConstraint
Definition: parsenodes.h:1979
@ AT_DropOf
Definition: parsenodes.h:2011
@ AT_CheckNotNull
Definition: parsenodes.h:1962
@ AT_SetOptions
Definition: parsenodes.h:1964
@ AT_DropIdentity
Definition: parsenodes.h:2023
@ AT_DisableTrigUser
Definition: parsenodes.h:2003
@ AT_DropNotNull
Definition: parsenodes.h:1959
@ AT_AddOf
Definition: parsenodes.h:2010
@ AT_ResetOptions
Definition: parsenodes.h:1965
@ AT_ReplicaIdentity
Definition: parsenodes.h:2012
@ AT_DropColumnRecurse
Definition: parsenodes.h:1969
@ AT_ReplaceRelOptions
Definition: parsenodes.h:1995
@ AT_EnableRowSecurity
Definition: parsenodes.h:2013
@ AT_AddColumnToView
Definition: parsenodes.h:1956
@ AT_ResetRelOptions
Definition: parsenodes.h:1994
@ AT_AddConstraintRecurse
Definition: parsenodes.h:1973
@ AT_EnableReplicaTrig
Definition: parsenodes.h:1998
@ AT_DropOids
Definition: parsenodes.h:1990
@ AT_SetIdentity
Definition: parsenodes.h:2022
@ AT_ReAddStatistics
Definition: parsenodes.h:2024
@ AT_SetUnLogged
Definition: parsenodes.h:1989
@ AT_DisableTrig
Definition: parsenodes.h:1999
@ AT_SetCompression
Definition: parsenodes.h:1967
@ AT_DropExpression
Definition: parsenodes.h:1961
@ AT_AddIndex
Definition: parsenodes.h:1970
@ AT_EnableReplicaRule
Definition: parsenodes.h:2006
@ AT_ReAddIndex
Definition: parsenodes.h:1971
@ AT_DropConstraint
Definition: parsenodes.h:1980
@ AT_SetNotNull
Definition: parsenodes.h:1960
@ AT_ClusterOn
Definition: parsenodes.h:1986
@ AT_AddIdentity
Definition: parsenodes.h:2021
@ AT_ForceRowSecurity
Definition: parsenodes.h:2015
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2005
@ AT_SetAccessMethod
Definition: parsenodes.h:1991
@ AT_AlterColumnType
Definition: parsenodes.h:1983
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2020
@ AT_AddInherit
Definition: parsenodes.h:2008
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:1975
@ AT_EnableTrig
Definition: parsenodes.h:1996
@ AT_AddColumnRecurse
Definition: parsenodes.h:1955
@ AT_DropColumn
Definition: parsenodes.h:1968
@ AT_ValidateConstraintRecurse
Definition: parsenodes.h:1978
@ AT_ReAddComment
Definition: parsenodes.h:1982
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:1984
@ AT_DisableTrigAll
Definition: parsenodes.h:2001
@ AT_EnableRule
Definition: parsenodes.h:2004
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2016
@ AT_DetachPartition
Definition: parsenodes.h:2019
@ AT_SetStatistics
Definition: parsenodes.h:1963
@ AT_AttachPartition
Definition: parsenodes.h:2018
@ AT_AddConstraint
Definition: parsenodes.h:1972
@ AT_DropInherit
Definition: parsenodes.h:2009
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:1997
@ AT_SetLogged
Definition: parsenodes.h:1988
@ AT_SetStorage
Definition: parsenodes.h:1966
@ AT_DisableRule
Definition: parsenodes.h:2007
@ AT_DisableRowSecurity
Definition: parsenodes.h:2014
@ AT_SetRelOptions
Definition: parsenodes.h:1993
@ AT_ChangeOwner
Definition: parsenodes.h:1985
@ AT_EnableTrigUser
Definition: parsenodes.h:2002
@ AT_ReAddConstraint
Definition: parsenodes.h:1974
@ AT_DropConstraintRecurse
Definition: parsenodes.h:1981
@ AT_SetTableSpace
Definition: parsenodes.h:1992
@ AT_GenericOptions
Definition: parsenodes.h:2017
@ AT_ColumnDefault
Definition: parsenodes.h:1957
@ AT_CookedColumnDefault
Definition: parsenodes.h:1958
@ AT_AlterConstraint
Definition: parsenodes.h:1976
@ AT_EnableTrigAll
Definition: parsenodes.h:2000
@ AT_DropCluster
Definition: parsenodes.h:1987
@ AT_ValidateConstraint
Definition: parsenodes.h:1977
@ AT_AddColumn
Definition: parsenodes.h:1954

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

Referenced by ATSimplePermissions().

◆ AlterIndexNamespaces()

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

Definition at line 16583 of file tablecmds.c.

16585 {
16586  List *indexList;
16587  ListCell *l;
16588 
16589  indexList = RelationGetIndexList(rel);
16590 
16591  foreach(l, indexList)
16592  {
16593  Oid indexOid = lfirst_oid(l);
16594  ObjectAddress thisobj;
16595 
16596  thisobj.classId = RelationRelationId;
16597  thisobj.objectId = indexOid;
16598  thisobj.objectSubId = 0;
16599 
16600  /*
16601  * Note: currently, the index will not have its own dependency on the
16602  * namespace, so we don't need to do changeDependencyFor(). There's no
16603  * row type in pg_type, either.
16604  *
16605  * XXX this objsMoved test may be pointless -- surely we have a single
16606  * dependency link from a relation to each index?
16607  */
16608  if (!object_address_present(&thisobj, objsMoved))
16609  {
16610  AlterRelationNamespaceInternal(classRel, indexOid,
16611  oldNspOid, newNspOid,
16612  false, objsMoved);
16613  add_exact_object_address(&thisobj, objsMoved);
16614  }
16615  }
16616 
16617  list_free(indexList);
16618 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2641
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2581
void list_free(List *list)
Definition: list.c:1545
#define lfirst_oid(lc)
Definition: pg_list.h:172
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4738
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16513

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

Referenced by AlterTableNamespaceInternal().

◆ AlterRelationNamespaceInternal()

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

Definition at line 16513 of file tablecmds.c.

16517 {
16518  HeapTuple classTup;
16519  Form_pg_class classForm;
16520  ObjectAddress thisobj;
16521  bool already_done = false;
16522 
16523  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
16524  if (!HeapTupleIsValid(classTup))
16525  elog(ERROR, "cache lookup failed for relation %u", relOid);
16526  classForm = (Form_pg_class) GETSTRUCT(classTup);
16527 
16528  Assert(classForm->relnamespace == oldNspOid);
16529 
16530  thisobj.classId = RelationRelationId;
16531  thisobj.objectId = relOid;
16532  thisobj.objectSubId = 0;
16533 
16534  /*
16535  * If the object has already been moved, don't move it again. If it's
16536  * already in the right place, don't move it, but still fire the object
16537  * access hook.
16538  */
16539  already_done = object_address_present(&thisobj, objsMoved);
16540  if (!already_done && oldNspOid != newNspOid)
16541  {
16542  /* check for duplicate name (more friendly than unique-index failure) */
16543  if (get_relname_relid(NameStr(classForm->relname),
16544  newNspOid) != InvalidOid)
16545  ereport(ERROR,
16546  (errcode(ERRCODE_DUPLICATE_TABLE),
16547  errmsg("relation \"%s\" already exists in schema \"%s\"",
16548  NameStr(classForm->relname),
16549  get_namespace_name(newNspOid))));
16550 
16551  /* classTup is a copy, so OK to scribble on */
16552  classForm->relnamespace = newNspOid;
16553 
16554  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
16555 
16556  /* Update dependency on schema if caller said so */
16557  if (hasDependEntry &&
16558  changeDependencyFor(RelationRelationId,
16559  relOid,
16560  NamespaceRelationId,
16561  oldNspOid,
16562  newNspOid) != 1)
16563  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
16564  NameStr(classForm->relname));
16565  }
16566  if (!already_done)
16567  {
16568  add_exact_object_address(&thisobj, objsMoved);
16569 
16570  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
16571  }
16572 
16573  heap_freetuple(classTup);
16574 }
#define NameStr(name)
Definition: c.h:682
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3331
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1867
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:456
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:600
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
@ RELOID
Definition: syscache.h:89

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

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

◆ AlterSeqNamespaces()

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

Definition at line 16628 of file tablecmds.c.

16631 {
16632  Relation depRel;
16633  SysScanDesc scan;
16634  ScanKeyData key[2];
16635  HeapTuple tup;
16636 
16637  /*
16638  * SERIAL sequences are those having an auto dependency on one of the
16639  * table's columns (we don't care *which* column, exactly).
16640  */
16641  depRel = table_open(DependRelationId, AccessShareLock);
16642 
16643  ScanKeyInit(&key[0],
16644  Anum_pg_depend_refclassid,
16645  BTEqualStrategyNumber, F_OIDEQ,
16646  ObjectIdGetDatum(RelationRelationId));
16647  ScanKeyInit(&key[1],
16648  Anum_pg_depend_refobjid,
16649  BTEqualStrategyNumber, F_OIDEQ,
16651  /* we leave refobjsubid unspecified */
16652 
16653  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
16654  NULL, 2, key);
16655 
16656  while (HeapTupleIsValid(tup = systable_getnext(scan)))
16657  {
16658  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
16659  Relation seqRel;
16660 
16661  /* skip dependencies other than auto dependencies on columns */
16662  if (depForm->refobjsubid == 0 ||
16663  depForm->classid != RelationRelationId ||
16664  depForm->objsubid != 0 ||
16665  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
16666  continue;
16667 
16668  /* Use relation_open just in case it's an index */
16669  seqRel = relation_open(depForm->objid, lockmode);
16670 
16671  /* skip non-sequence relations */
16672  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
16673  {
16674  /* No need to keep the lock */
16675  relation_close(seqRel, lockmode);
16676  continue;
16677  }
16678 
16679  /* Fix the pg_class and pg_depend entries */
16680  AlterRelationNamespaceInternal(classRel, depForm->objid,
16681  oldNspOid, newNspOid,
16682  true, objsMoved);
16683 
16684  /*
16685  * Sequences used to have entries in pg_type, but no longer do. If we
16686  * ever re-instate that, we'll need to move the pg_type entry to the
16687  * new namespace, too (using AlterTypeNamespaceInternal).
16688  */
16689  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
16690 
16691  /* Now we can close it. Keep the lock till end of transaction. */
16692  relation_close(seqRel, NoLock);
16693  }
16694 
16695  systable_endscan(scan);
16696 
16698 }
@ DEPENDENCY_AUTO
Definition: dependency.h:34
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
#define AccessShareLock
Definition: lockdefs.h:36
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
#define RelationGetForm(relation)
Definition: rel.h:495
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define BTEqualStrategyNumber
Definition: stratnum.h:31

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

Referenced by AlterTableNamespaceInternal().

◆ AlterTable()

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

Definition at line 4092 of file tablecmds.c.

4094 {
4095  Relation rel;
4096 
4097  /* Caller is required to provide an adequate lock. */
4098  rel = relation_open(context->relid, NoLock);
4099 
4100  CheckTableNotInUse(rel, "ALTER TABLE");
4101 
4102  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4103 }
RangeVar * relation
Definition: parsenodes.h:1946
bool inh
Definition: primnodes.h:80
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4437

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

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4166 of file tablecmds.c.

4167 {
4168  /*
4169  * This only works if we read catalog tables using MVCC snapshots.
4170  */
4171  ListCell *lcmd;
4173 
4174  foreach(lcmd, cmds)
4175  {
4176  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4177  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4178 
4179  switch (cmd->subtype)
4180  {
4181  /*
4182  * These subcommands rewrite the heap, so require full locks.
4183  */
4184  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4185  * to SELECT */
4186  case AT_SetAccessMethod: /* must rewrite heap */
4187  case AT_SetTableSpace: /* must rewrite heap */
4188  case AT_AlterColumnType: /* must rewrite heap */
4189  cmd_lockmode = AccessExclusiveLock;
4190  break;
4191 
4192  /*
4193  * These subcommands may require addition of toast tables. If
4194  * we add a toast table to a table currently being scanned, we
4195  * might miss data added to the new toast table by concurrent
4196  * insert transactions.
4197  */
4198  case AT_SetStorage: /* may add toast tables, see
4199  * ATRewriteCatalogs() */
4200  cmd_lockmode = AccessExclusiveLock;
4201  break;
4202 
4203  /*
4204  * Removing constraints can affect SELECTs that have been
4205  * optimized assuming the constraint holds true. See also
4206  * CloneFkReferenced.
4207  */
4208  case AT_DropConstraint: /* as DROP INDEX */
4209  case AT_DropNotNull: /* may change some SQL plans */
4210  cmd_lockmode = AccessExclusiveLock;
4211  break;
4212 
4213  /*
4214  * Subcommands that may be visible to concurrent SELECTs
4215  */
4216  case AT_DropColumn: /* change visible to SELECT */
4217  case AT_AddColumnToView: /* CREATE VIEW */
4218  case AT_DropOids: /* used to equiv to DropColumn */
4219  case AT_EnableAlwaysRule: /* may change SELECT rules */
4220  case AT_EnableReplicaRule: /* may change SELECT rules */
4221  case AT_EnableRule: /* may change SELECT rules */
4222  case AT_DisableRule: /* may change SELECT rules */
4223  cmd_lockmode = AccessExclusiveLock;
4224  break;
4225 
4226  /*
4227  * Changing owner may remove implicit SELECT privileges
4228  */
4229  case AT_ChangeOwner: /* change visible to SELECT */
4230  cmd_lockmode = AccessExclusiveLock;
4231  break;
4232 
4233  /*
4234  * Changing foreign table options may affect optimization.
4235  */
4236  case AT_GenericOptions:
4238  cmd_lockmode = AccessExclusiveLock;
4239  break;
4240 
4241  /*
4242  * These subcommands affect write operations only.
4243  */
4244  case AT_EnableTrig:
4245  case AT_EnableAlwaysTrig:
4246  case AT_EnableReplicaTrig:
4247  case AT_EnableTrigAll:
4248  case AT_EnableTrigUser:
4249  case AT_DisableTrig:
4250  case AT_DisableTrigAll:
4251  case AT_DisableTrigUser:
4252  cmd_lockmode = ShareRowExclusiveLock;
4253  break;
4254 
4255  /*
4256  * These subcommands affect write operations only. XXX
4257  * Theoretically, these could be ShareRowExclusiveLock.
4258  */
4259  case AT_ColumnDefault:
4261  case AT_AlterConstraint:
4262  case AT_AddIndex: /* from ADD CONSTRAINT */
4263  case AT_AddIndexConstraint:
4264  case AT_ReplicaIdentity:
4265  case AT_SetNotNull:
4266  case AT_EnableRowSecurity:
4267  case AT_DisableRowSecurity:
4268  case AT_ForceRowSecurity:
4269  case AT_NoForceRowSecurity:
4270  case AT_AddIdentity:
4271  case AT_DropIdentity:
4272  case AT_SetIdentity:
4273  case AT_DropExpression:
4274  case AT_SetCompression:
4275  cmd_lockmode = AccessExclusiveLock;
4276  break;
4277 
4278  case AT_AddConstraint:
4279  case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
4280  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4281  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4282  if (IsA(cmd->def, Constraint))
4283  {
4284  Constraint *con = (Constraint *) cmd->def;
4285 
4286  switch (con->contype)
4287  {
4288  case CONSTR_EXCLUSION:
4289  case CONSTR_PRIMARY:
4290  case CONSTR_UNIQUE:
4291 
4292  /*
4293  * Cases essentially the same as CREATE INDEX. We
4294  * could reduce the lock strength to ShareLock if
4295  * we can work out how to allow concurrent catalog
4296  * updates. XXX Might be set down to
4297  * ShareRowExclusiveLock but requires further
4298  * analysis.
4299  */
4300  cmd_lockmode = AccessExclusiveLock;
4301  break;
4302  case CONSTR_FOREIGN:
4303 
4304  /*
4305  * We add triggers to both tables when we add a
4306  * Foreign Key, so the lock level must be at least
4307  * as strong as CREATE TRIGGER.
4308  */
4309  cmd_lockmode = ShareRowExclusiveLock;
4310  break;
4311 
4312  default:
4313  cmd_lockmode = AccessExclusiveLock;
4314  }
4315  }
4316  break;
4317 
4318  /*
4319  * These subcommands affect inheritance behaviour. Queries
4320  * started before us will continue to see the old inheritance
4321  * behaviour, while queries started after we commit will see
4322  * new behaviour. No need to prevent reads or writes to the
4323  * subtable while we hook it up though. Changing the TupDesc
4324  * may be a problem, so keep highest lock.
4325  */
4326  case AT_AddInherit:
4327  case AT_DropInherit:
4328  cmd_lockmode = AccessExclusiveLock;
4329  break;
4330 
4331  /*
4332  * These subcommands affect implicit row type conversion. They
4333  * have affects similar to CREATE/DROP CAST on queries. don't
4334  * provide for invalidating parse trees as a result of such
4335  * changes, so we keep these at AccessExclusiveLock.
4336  */
4337  case AT_AddOf:
4338  case AT_DropOf:
4339  cmd_lockmode = AccessExclusiveLock;
4340  break;
4341 
4342  /*
4343  * Only used by CREATE OR REPLACE VIEW which must conflict
4344  * with an SELECTs currently using the view.
4345  */
4346  case AT_ReplaceRelOptions:
4347  cmd_lockmode = AccessExclusiveLock;
4348  break;
4349 
4350  /*
4351  * These subcommands affect general strategies for performance
4352  * and maintenance, though don't change the semantic results
4353  * from normal data reads and writes. Delaying an ALTER TABLE
4354  * behind currently active writes only delays the point where
4355  * the new strategy begins to take effect, so there is no
4356  * benefit in waiting. In this case the minimum restriction
4357  * applies: we don't currently allow concurrent catalog
4358  * updates.
4359  */
4360  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4361  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4362  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4363  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4364  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4365  cmd_lockmode = ShareUpdateExclusiveLock;
4366  break;
4367 
4368  case AT_SetLogged:
4369  case AT_SetUnLogged:
4370  cmd_lockmode = AccessExclusiveLock;
4371  break;
4372 
4373  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4374  cmd_lockmode = ShareUpdateExclusiveLock;
4375  break;
4376 
4377  /*
4378  * Rel options are more complex than first appears. Options
4379  * are set here for tables, views and indexes; for historical
4380  * reasons these can all be used with ALTER TABLE, so we can't
4381  * decide between them using the basic grammar.
4382  */
4383  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4384  * getTables() */
4385  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4386  * getTables() */
4387  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4388  break;
4389 
4390  case AT_AttachPartition:
4391  cmd_lockmode = ShareUpdateExclusiveLock;
4392  break;
4393 
4394  case AT_DetachPartition:
4395  if (((PartitionCmd *) cmd->def)->concurrent)
4396  cmd_lockmode = ShareUpdateExclusiveLock;
4397  else
4398  cmd_lockmode = AccessExclusiveLock;
4399  break;
4400 
4402  cmd_lockmode = ShareUpdateExclusiveLock;
4403  break;
4404 
4405  case AT_CheckNotNull:
4406 
4407  /*
4408  * This only examines the table's schema; but lock must be
4409  * strong enough to prevent concurrent DROP NOT NULL.
4410  */
4411  cmd_lockmode = AccessShareLock;
4412  break;
4413 
4414  default: /* oops */
4415  elog(ERROR, "unrecognized alter table type: %d",
4416  (int) cmd->subtype);
4417  break;
4418  }
4419 
4420  /*
4421  * Take the greatest lockmode from any subcommand
4422  */
4423  if (cmd_lockmode > lockmode)
4424  lockmode = cmd_lockmode;
4425  }
4426 
4427  return lockmode;
4428 }
int LOCKMODE
Definition: lockdefs.h:26
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define IsA(nodeptr, _type_)
Definition: nodes.h:168
@ CONSTR_UNIQUE
Definition: parsenodes.h:2315
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2316
@ CONSTR_PRIMARY
Definition: parsenodes.h:2314
#define lfirst(lc)
Definition: pg_list.h:170
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2109
AlterTableType subtype
Definition: parsenodes.h:2037
ConstrType contype
Definition: parsenodes.h:2341

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

Referenced by AlterTableInternal(), and ProcessUtilitySlow().

◆ AlterTableInternal()

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

Definition at line 4121 of file tablecmds.c.

4122 {
4123  Relation rel;
4124  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4125 
4126  rel = relation_open(relid, lockmode);
4127 
4129 
4130  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4131 }
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4166

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4032 of file tablecmds.c.

4033 {
4034  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4035  stmt->missing_ok ? RVR_MISSING_OK : 0,
4037  (void *) stmt);
4038 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:239
@ RVR_MISSING_OK
Definition: namespace.h:71
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:17026

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

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 14514 of file tablecmds.c.

14515 {
14516  List *relations = NIL;
14517  ListCell *l;
14518  ScanKeyData key[1];
14519  Relation rel;
14520  TableScanDesc scan;
14521  HeapTuple tuple;
14522  Oid orig_tablespaceoid;
14523  Oid new_tablespaceoid;
14524  List *role_oids = roleSpecsToIds(stmt->roles);
14525 
14526  /* Ensure we were not asked to move something we can't */
14527  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
14528  stmt->objtype != OBJECT_MATVIEW)
14529  ereport(ERROR,
14530  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14531  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
14532 
14533  /* Get the orig and new tablespace OIDs */
14534  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
14535  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
14536 
14537  /* Can't move shared relations in to or out of pg_global */
14538  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
14539  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
14540  new_tablespaceoid == GLOBALTABLESPACE_OID)
14541  ereport(ERROR,
14542  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14543  errmsg("cannot move relations in to or out of pg_global tablespace")));
14544 
14545  /*
14546  * Must have CREATE rights on the new tablespace, unless it is the
14547  * database default tablespace (which all users implicitly have CREATE
14548  * rights on).
14549  */
14550  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
14551  {
14552  AclResult aclresult;
14553 
14554  aclresult = object_aclcheck(TableSpaceRelationId, new_tablespaceoid, GetUserId(),
14555  ACL_CREATE);
14556  if (aclresult != ACLCHECK_OK)
14557  aclcheck_error(aclresult, OBJECT_TABLESPACE,
14558  get_tablespace_name(new_tablespaceoid));
14559  }
14560 
14561  /*
14562  * Now that the checks are done, check if we should set either to
14563  * InvalidOid because it is our database's default tablespace.
14564  */
14565  if (orig_tablespaceoid == MyDatabaseTableSpace)
14566  orig_tablespaceoid = InvalidOid;
14567 
14568  if (new_tablespaceoid == MyDatabaseTableSpace)
14569  new_tablespaceoid = InvalidOid;
14570 
14571  /* no-op */
14572  if (orig_tablespaceoid == new_tablespaceoid)
14573  return new_tablespaceoid;
14574 
14575  /*
14576  * Walk the list of objects in the tablespace and move them. This will
14577  * only find objects in our database, of course.
14578  */
14579  ScanKeyInit(&key[0],
14580  Anum_pg_class_reltablespace,
14581  BTEqualStrategyNumber, F_OIDEQ,
14582  ObjectIdGetDatum(orig_tablespaceoid));
14583 
14584  rel = table_open(RelationRelationId, AccessShareLock);
14585  scan = table_beginscan_catalog(rel, 1, key);
14586  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
14587  {
14588  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
14589  Oid relOid = relForm->oid;
14590 
14591  /*
14592  * Do not move objects in pg_catalog as part of this, if an admin
14593  * really wishes to do so, they can issue the individual ALTER
14594  * commands directly.
14595  *
14596  * Also, explicitly avoid any shared tables, temp tables, or TOAST
14597  * (TOAST will be moved with the main table).
14598  */
14599  if (IsCatalogNamespace(relForm->relnamespace) ||
14600  relForm->relisshared ||
14601  isAnyTempNamespace(relForm->relnamespace) ||
14602  IsToastNamespace(relForm->relnamespace))
14603  continue;
14604 
14605  /* Only move the object type requested */
14606  if ((stmt->objtype == OBJECT_TABLE &&
14607  relForm->relkind != RELKIND_RELATION &&
14608  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
14609  (stmt->objtype == OBJECT_INDEX &&
14610  relForm->relkind != RELKIND_INDEX &&
14611  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
14612  (stmt->objtype == OBJECT_MATVIEW &&
14613  relForm->relkind != RELKIND_MATVIEW))
14614  continue;
14615 
14616  /* Check if we are only moving objects owned by certain roles */
14617  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
14618  continue;
14619 
14620  /*
14621  * Handle permissions-checking here since we are locking the tables
14622  * and also to avoid doing a bunch of work only to fail part-way. Note
14623  * that permissions will also be checked by AlterTableInternal().
14624  *
14625  * Caller must be considered an owner on the table to move it.
14626  */
14627  if (!object_ownercheck(RelationRelationId, relOid, GetUserId()))
14629  NameStr(relForm->relname));
14630 
14631  if (stmt->nowait &&
14633  ereport(ERROR,
14634  (errcode(ERRCODE_OBJECT_IN_USE),
14635  errmsg("aborting because lock on relation \"%s.%s\" is not available",
14636  get_namespace_name(relForm->relnamespace),
14637  NameStr(relForm->relname))));
14638  else
14640 
14641  /* Add to our list of objects to move */
14642  relations = lappend_oid(relations, relOid);
14643  }
14644 
14645  table_endscan(scan);
14647 
14648  if (relations == NIL)
14649  ereport(NOTICE,
14650  (errcode(ERRCODE_NO_DATA_FOUND),
14651  errmsg("no matching relations in tablespace \"%s\" found",
14652  orig_tablespaceoid == InvalidOid ? "(database default)" :
14653  get_tablespace_name(orig_tablespaceoid))));
14654 
14655  /* Everything is locked, loop through and move all of the relations. */
14656  foreach(l, relations)
14657  {
14658  List *cmds = NIL;
14660 
14661  cmd->subtype = AT_SetTableSpace;
14662  cmd->name = stmt->new_tablespacename;
14663 
14664  cmds = lappend(cmds, cmd);
14665 
14667  /* OID is set by AlterTableInternal */
14668  AlterTableInternal(lfirst_oid(l), cmds, false);
14670  }
14671 
14672  return new_tablespaceoid;
14673 }
AclResult
Definition: acl.h:183
@ ACLCHECK_OK
Definition: acl.h:184
@ ACLCHECK_NOT_OWNER
Definition: acl.h:186
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3485
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:4598
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4799
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1478
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1432
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:202
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:184
#define NOTICE
Definition: elog.h:31
void EventTriggerAlterTableStart(Node *parsetree)
void EventTriggerAlterTableEnd(void)
Oid MyDatabaseTableSpace
Definition: globals.c:91
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1299
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:721
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:152
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:109
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1985
Oid GetUserId(void)
Definition: miscinit.c:497
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3238
#define makeNode(_type_)
Definition: nodes.h:165
ObjectType get_relkind_objtype(char relkind)
@ OBJECT_MATVIEW
Definition: parsenodes.h:1885
@ OBJECT_TABLESPACE
Definition: parsenodes.h:1904
@ OBJECT_INDEX
Definition: parsenodes.h:1882
@ OBJECT_TABLE
Definition: parsenodes.h:1903
#define ACL_CREATE
Definition: parsenodes.h:92
@ ForwardScanDirection
Definition: sdir.h:26
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:993
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4121
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1530

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_aclcheck(), OBJECT_INDEX, OBJECT_MATVIEW, object_ownercheck(), OBJECT_TABLE, OBJECT_TABLESPACE, ObjectIdGetDatum(), AlterTableMoveAllStmt::objtype, OidIsValid, AlterTableMoveAllStmt::orig_tablespacename, AlterTableMoveAllStmt::roles, roleSpecsToIds(), ScanKeyInit(), AlterTableCmd::subtype, table_beginscan_catalog(), table_close(), table_endscan(), and table_open().

Referenced by ProcessUtilitySlow().

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 16403 of file tablecmds.c.

16404 {
16405  Relation rel;
16406  Oid relid;
16407  Oid oldNspOid;
16408  Oid nspOid;
16409  RangeVar *newrv;
16410  ObjectAddresses *objsMoved;
16411  ObjectAddress myself;
16412 
16414  stmt->missing_ok ? RVR_MISSING_OK : 0,
16416  (void *) stmt);
16417 
16418  if (!OidIsValid(relid))
16419  {
16420  ereport(NOTICE,
16421  (errmsg("relation \"%s\" does not exist, skipping",
16422  stmt->relation->relname)));
16423  return InvalidObjectAddress;
16424  }
16425 
16426  rel = relation_open(relid, NoLock);
16427 
16428  oldNspOid = RelationGetNamespace(rel);
16429 
16430  /* If it's an owned sequence, disallow moving it by itself. */
16431  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
16432  {
16433  Oid tableId;
16434  int32 colId;
16435 
16436  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
16437  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
16438  ereport(ERROR,
16439  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16440  errmsg("cannot move an owned sequence into another schema"),
16441  errdetail("Sequence \"%s\" is linked to table \"%s\".",
16443  get_rel_name(tableId))));
16444  }
16445 
16446  /* Get and lock schema OID and check its permissions. */
16447  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
16448  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
16449 
16450  /* common checks on switching namespaces */
16451  CheckSetNamespace(oldNspOid, nspOid);
16452 
16453  objsMoved = new_object_addresses();
16454  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
16455  free_object_addresses(objsMoved);
16456 
16457  ObjectAddressSet(myself, RelationRelationId, relid);
16458 
16459  if (oldschema)
16460  *oldschema = oldNspOid;
16461 
16462  /* close rel, but keep lock until commit */
16463  relation_close(rel, NoLock);
16464 
16465  return myself;
16466 }
signed int int32
Definition: c.h:430
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2526
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2821
int errdetail(const char *fmt,...)
Definition: elog.c:1039
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1910
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:422
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:537
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3010
const ObjectAddress InvalidObjectAddress
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:827
char * relname
Definition: primnodes.h:77
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16474

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(), AlterObjectSchemaStmt::newschema, NoLock, NOTICE, ObjectAddressSet, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelidExtended(), RelationData::rd_rel, AlterObjectSchemaStmt::relation, relation_close(), relation_open(), RelationGetNamespace, RelationGetRelationName, RangeVar::relname, RVR_MISSING_OK, and sequenceIsOwned().

Referenced by ExecAlterObjectSchemaStmt().

◆ AlterTableNamespaceInternal()

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

Definition at line 16474 of file tablecmds.c.

16476 {
16477  Relation classRel;
16478 
16479  Assert(objsMoved != NULL);
16480 
16481  /* OK, modify the pg_class row and pg_depend entry */
16482  classRel = table_open(RelationRelationId, RowExclusiveLock);
16483 
16484  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
16485  nspOid, true, objsMoved);
16486 
16487  /* Fix the table's row type too, if it has one */
16488  if (OidIsValid(rel->rd_rel->reltype))
16489  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
16490  nspOid, false, false, objsMoved);
16491 
16492  /* Fix other dependent stuff */
16493  if (rel->rd_rel->relkind == RELKIND_RELATION ||
16494  rel->rd_rel->relkind == RELKIND_MATVIEW ||
16495  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16496  {
16497  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
16498  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
16499  objsMoved, AccessExclusiveLock);
16500  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
16501  false, objsMoved);
16502  }
16503 
16504  table_close(classRel, RowExclusiveLock);
16505 }
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:16628
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16583
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3952

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

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

◆ ATAddCheckConstraint()

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

Definition at line 8881 of file tablecmds.c.

8884 {
8885  List *newcons;
8886  ListCell *lcon;
8887  List *children;
8888  ListCell *child;
8890 
8891  /* At top level, permission check was done in ATPrepCmd, else do it */
8892  if (recursing)
8894 
8895  /*
8896  * Call AddRelationNewConstraints to do the work, making sure it works on
8897  * a copy of the Constraint so transformExpr can't modify the original. It
8898  * returns a list of cooked constraints.
8899  *
8900  * If the constraint ends up getting merged with a pre-existing one, it's
8901  * omitted from the returned list, which is what we want: we do not need
8902  * to do any validation work. That can only happen at child tables,
8903  * though, since we disallow merging at the top level.
8904  */
8905  newcons = AddRelationNewConstraints(rel, NIL,
8906  list_make1(copyObject(constr)),
8907  recursing | is_readd, /* allow_merge */
8908  !recursing, /* is_local */
8909  is_readd, /* is_internal */
8910  NULL); /* queryString not available
8911  * here */
8912 
8913  /* we don't expect more than one constraint here */
8914  Assert(list_length(newcons) <= 1);
8915 
8916  /* Add each to-be-validated constraint to Phase 3's queue */
8917  foreach(lcon, newcons)
8918  {
8919  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
8920 
8921  if (!ccon->skip_validation)
8922  {
8923  NewConstraint *newcon;
8924 
8925  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
8926  newcon->name = ccon->name;
8927  newcon->contype = ccon->contype;
8928  newcon->qual = ccon->expr;
8929 
8930  tab->constraints = lappend(tab->constraints, newcon);
8931  }
8932 
8933  /* Save the actually assigned name if it was defaulted */
8934  if (constr->conname == NULL)
8935  constr->conname = ccon->name;
8936 
8937  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
8938  }
8939 
8940  /* At this point we must have a locked-down name to use */
8941  Assert(constr->conname != NULL);
8942 
8943  /* Advance command counter in case same table is visited multiple times */
8945 
8946  /*
8947  * If the constraint got merged with an existing constraint, we're done.
8948  * We mustn't recurse to child tables in this case, because they've
8949  * already got the constraint, and visiting them again would lead to an
8950  * incorrect value for coninhcount.
8951  */
8952  if (newcons == NIL)
8953  return address;
8954 
8955  /*
8956  * If adding a NO INHERIT constraint, no need to find our children.
8957  */
8958  if (constr->is_no_inherit)
8959  return address;
8960 
8961  /*
8962  * Propagate to children as appropriate. Unlike most other ALTER
8963  * routines, we have to do this one level of recursion at a time; we can't
8964  * use find_all_inheritors to do it in one pass.
8965  */
8966  children =
8968 
8969  /*
8970  * Check if ONLY was specified with ALTER TABLE. If so, allow the
8971  * constraint creation only if there are no children currently. Error out
8972  * otherwise.
8973  */
8974  if (!recurse && children != NIL)
8975  ereport(ERROR,
8976  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8977  errmsg("constraint must be added to child tables too")));
8978 
8979  foreach(child, children)
8980  {
8981  Oid childrelid = lfirst_oid(child);
8982  Relation childrel;
8983  AlteredTableInfo *childtab;
8984 
8985  /* find_inheritance_children already got lock */
8986  childrel = table_open(childrelid, NoLock);
8987  CheckTableNotInUse(childrel, "ALTER TABLE");
8988 
8989  /* Find or create work queue entry for this table */
8990  childtab = ATGetQueueEntry(wqueue, childrel);
8991 
8992  /* Recurse to child */
8993  ATAddCheckConstraint(wqueue, childtab, childrel,
8994  constr, recurse, true, is_readd, lockmode);
8995 
8996  table_close(childrel, NoLock);
8997  }
8998 
8999  return address;
9000 }
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2246
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:59
static int list_length(const List *l)
Definition: pg_list.h:150
#define list_make1(x1)
Definition: pg_list.h:210
bool is_no_inherit
Definition: parsenodes.h:2350
Oid conoid
Definition: heap.h:38
char * name
Definition: heap.h:39
bool skip_validation
Definition: heap.h:42
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:41
#define ATT_TABLE
Definition: tablecmds.c:315
static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
Definition: tablecmds.c:6256
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:320
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:8881

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

Referenced by ATExecAddConstraint(), and DetachAddConstraintIfNeeded().

◆ ATAddForeignKeyConstraint()

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

Definition at line 9018 of file tablecmds.c.

9021 {
9022  Relation pkrel;
9023  int16 pkattnum[INDEX_MAX_KEYS] = {0};
9024  int16 fkattnum[INDEX_MAX_KEYS] = {0};
9025  Oid pktypoid[INDEX_MAX_KEYS] = {0};
9026  Oid fktypoid[INDEX_MAX_KEYS] = {0};
9027  Oid opclasses[INDEX_MAX_KEYS] = {0};
9028  Oid pfeqoperators[INDEX_MAX_KEYS] = {0};
9029  Oid ppeqoperators[INDEX_MAX_KEYS] = {0};
9030  Oid ffeqoperators[INDEX_MAX_KEYS] = {0};
9031  int16 fkdelsetcols[INDEX_MAX_KEYS] = {0};
9032  int i;
9033  int numfks,
9034  numpks,
9035  numfkdelsetcols;
9036  Oid indexOid;
9037  bool old_check_ok;
9038  ObjectAddress address;
9039  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
9040 
9041  /*
9042  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
9043  * delete rows out from under us.
9044  */
9045  if (OidIsValid(fkconstraint->old_pktable_oid))
9046  pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
9047  else
9048  pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
9049 
9050  /*
9051  * Validity checks (permission checks wait till we have the column
9052  * numbers)
9053  */
9054  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9055  {
9056  if (!recurse)
9057  ereport(ERROR,
9058  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9059  errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9061  RelationGetRelationName(pkrel))));
9062  if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
9063  ereport(ERROR,
9064  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9065  errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
9067  RelationGetRelationName(pkrel)),
9068  errdetail("This feature is not yet supported on partitioned tables.")));
9069  }
9070 
9071  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9072  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9073  ereport(ERROR,
9074  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9075  errmsg("referenced relation \"%s\" is not a table",
9076  RelationGetRelationName(pkrel))));
9077 
9078  if (!allowSystemTableMods && IsSystemRelation(pkrel))
9079  ereport(ERROR,
9080  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
9081  errmsg("permission denied: \"%s\" is a system catalog",
9082  RelationGetRelationName(pkrel))));
9083 
9084  /*
9085  * References from permanent or unlogged tables to temp tables, and from
9086  * permanent tables to unlogged tables, are disallowed because the
9087  * referenced data can vanish out from under us. References from temp
9088  * tables to any other table type are also disallowed, because other
9089  * backends might need to run the RI triggers on the perm table, but they
9090  * can't reliably see tuples in the local buffers of other backends.
9091  */
9092  switch (rel->rd_rel->relpersistence)
9093  {
9094  case RELPERSISTENCE_PERMANENT:
9095  if (!RelationIsPermanent(pkrel))
9096  ereport(ERROR,
9097  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9098  errmsg("constraints on permanent tables may reference only permanent tables")));
9099  break;
9100  case RELPERSISTENCE_UNLOGGED:
9101  if (!RelationIsPermanent(pkrel)
9102  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
9103  ereport(ERROR,
9104  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9105  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
9106  break;
9107  case RELPERSISTENCE_TEMP:
9108  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
9109  ereport(ERROR,
9110  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9111  errmsg("constraints on temporary tables may reference only temporary tables")));
9112  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
9113  ereport(ERROR,
9114  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9115  errmsg("constraints on temporary tables must involve temporary tables of this session")));
9116  break;
9117  }
9118 
9119  /*
9120  * Look up the referencing attributes to make sure they exist, and record
9121  * their attnums and type OIDs.
9122  */
9124  fkconstraint->fk_attrs,
9125  fkattnum, fktypoid);
9126 
9127  numfkdelsetcols = transformColumnNameList(RelationGetRelid(rel),
9128  fkconstraint->fk_del_set_cols,
9129  fkdelsetcols, NULL);
9130  validateFkOnDeleteSetColumns(numfks, fkattnum,
9131  numfkdelsetcols, fkdelsetcols,
9132  fkconstraint->fk_del_set_cols);
9133 
9134  /*
9135  * If the attribute list for the referenced table was omitted, lookup the
9136  * definition of the primary key and use it. Otherwise, validate the
9137  * supplied attribute list. In either case, discover the index OID and
9138  * index opclasses, and the attnums and type OIDs of the attributes.
9139  */
9140  if (fkconstraint->pk_attrs == NIL)
9141  {
9142  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
9143  &fkconstraint->pk_attrs,
9144  pkattnum, pktypoid,
9145  opclasses);
9146  }
9147  else
9148  {
9149  numpks = transformColumnNameList(RelationGetRelid(pkrel),
9150  fkconstraint->pk_attrs,
9151  pkattnum, pktypoid);
9152  /* Look for an index matching the column list */
9153  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
9154  opclasses);
9155  }
9156 
9157  /*
9158  * Now we can check permissions.
9159  */
9160  checkFkeyPermissions(pkrel, pkattnum, numpks);
9161 
9162  /*
9163  * Check some things for generated columns.
9164  */
9165  for (i = 0; i < numfks; i++)
9166  {
9167  char attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
9168 
9169  if (attgenerated)
9170  {
9171  /*
9172  * Check restrictions on UPDATE/DELETE actions, per SQL standard
9173  */
9174  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
9175  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
9176  fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
9177  ereport(ERROR,
9178  (errcode(ERRCODE_SYNTAX_ERROR),
9179  errmsg("invalid %s action for foreign key constraint containing generated column",
9180  "ON UPDATE")));
9181  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
9182  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
9183  ereport(ERROR,
9184  (errcode(ERRCODE_SYNTAX_ERROR),
9185  errmsg("invalid %s action for foreign key constraint containing generated column",
9186  "ON DELETE")));
9187  }
9188  }
9189 
9190  /*
9191  * Look up the equality operators to use in the constraint.
9192  *
9193  * Note that we have to be careful about the difference between the actual
9194  * PK column type and the opclass' declared input type, which might be
9195  * only binary-compatible with it. The declared opcintype is the right
9196  * thing to probe pg_amop with.
9197  */
9198  if (numfks != numpks)
9199  ereport(ERROR,
9200  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
9201  errmsg("number of referencing and referenced columns for foreign key disagree")));
9202 
9203  /*
9204  * On the strength of a previous constraint, we might avoid scanning
9205  * tables to validate this one. See below.
9206  */
9207  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
9208  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
9209 
9210  for (i = 0; i < numpks; i++)
9211  {
9212  Oid pktype = pktypoid[i];
9213  Oid fktype = fktypoid[i];
9214  Oid fktyped;
9215  HeapTuple cla_ht;
9216  Form_pg_opclass cla_tup;
9217  Oid amid;
9218  Oid opfamily;
9219  Oid opcintype;
9220  Oid pfeqop;
9221  Oid ppeqop;
9222  Oid ffeqop;
9223  int16 eqstrategy;
9224  Oid pfeqop_right;
9225 
9226  /* We need several fields out of the pg_opclass entry */
9227  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
9228  if (!HeapTupleIsValid(cla_ht))
9229  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
9230  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
9231  amid = cla_tup->opcmethod;
9232  opfamily = cla_tup->opcfamily;
9233  opcintype = cla_tup->opcintype;
9234  ReleaseSysCache(cla_ht);
9235 
9236  /*
9237  * Check it's a btree; currently this can never fail since no other
9238  * index AMs support unique indexes. If we ever did have other types
9239  * of unique indexes, we'd need a way to determine which operator
9240  * strategy number is equality. (Is it reasonable to insist that
9241  * every such index AM use btree's number for equality?)
9242  */
9243  if (amid != BTREE_AM_OID)
9244  elog(ERROR, "only b-tree indexes are supported for foreign keys");
9245  eqstrategy = BTEqualStrategyNumber;
9246 
9247  /*
9248  * There had better be a primary equality operator for the index.
9249  * We'll use it for PK = PK comparisons.
9250  */
9251  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
9252  eqstrategy);
9253 
9254  if (!OidIsValid(ppeqop))
9255  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
9256  eqstrategy, opcintype, opcintype, opfamily);
9257 
9258  /*
9259  * Are there equality operators that take exactly the FK type? Assume
9260  * we should look through any domain here.
9261  */
9262  fktyped = getBaseType(fktype);
9263 
9264  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
9265  eqstrategy);
9266  if (OidIsValid(pfeqop))
9267  {
9268  pfeqop_right = fktyped;
9269  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
9270  eqstrategy);
9271  }
9272  else
9273  {
9274  /* keep compiler quiet */
9275  pfeqop_right = InvalidOid;
9276  ffeqop = InvalidOid;
9277  }
9278 
9279  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9280  {
9281  /*
9282  * Otherwise, look for an implicit cast from the FK type to the
9283  * opcintype, and if found, use the primary equality operator.
9284  * This is a bit tricky because opcintype might be a polymorphic
9285  * type such as ANYARRAY or ANYENUM; so what we have to test is
9286  * whether the two actual column types can be concurrently cast to
9287  * that type. (Otherwise, we'd fail to reject combinations such
9288  * as int[] and point[].)
9289  */
9290  Oid input_typeids[2];
9291  Oid target_typeids[2];
9292 
9293  input_typeids[0] = pktype;
9294  input_typeids[1] = fktype;
9295  target_typeids[0] = opcintype;
9296  target_typeids[1] = opcintype;
9297  if (can_coerce_type(2, input_typeids, target_typeids,
9299  {
9300  pfeqop = ffeqop = ppeqop;
9301  pfeqop_right = opcintype;
9302  }
9303  }
9304 
9305  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9306  ereport(ERROR,
9307  (errcode(ERRCODE_DATATYPE_MISMATCH),
9308  errmsg("foreign key constraint \"%s\" cannot be implemented",
9309  fkconstraint->conname),
9310  errdetail("Key columns \"%s\" and \"%s\" "
9311  "are of incompatible types: %s and %s.",
9312  strVal(list_nth(fkconstraint->fk_attrs, i)),
9313  strVal(list_nth(fkconstraint->pk_attrs, i)),
9314  format_type_be(fktype),
9315  format_type_be(pktype))));
9316 
9317  if (old_check_ok)
9318  {
9319  /*
9320  * When a pfeqop changes, revalidate the constraint. We could
9321  * permit intra-opfamily changes, but that adds subtle complexity
9322  * without any concrete benefit for core types. We need not
9323  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
9324  */
9325  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
9326  old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
9327  old_pfeqop_item);
9328  }
9329  if (old_check_ok)
9330  {
9331  Oid old_fktype;
9332  Oid new_fktype;
9333  CoercionPathType old_pathtype;
9334  CoercionPathType new_pathtype;
9335  Oid old_castfunc;
9336  Oid new_castfunc;
9338  fkattnum[i] - 1);
9339 
9340  /*
9341  * Identify coercion pathways from each of the old and new FK-side
9342  * column types to the right (foreign) operand type of the pfeqop.
9343  * We may assume that pg_constraint.conkey is not changing.
9344  */
9345  old_fktype = attr->atttypid;
9346  new_fktype = fktype;
9347  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
9348  &old_castfunc);
9349  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
9350  &new_castfunc);
9351 
9352  /*
9353  * Upon a change to the cast from the FK column to its pfeqop
9354  * operand, revalidate the constraint. For this evaluation, a
9355  * binary coercion cast is equivalent to no cast at all. While
9356  * type implementors should design implicit casts with an eye
9357  * toward consistency of operations like equality, we cannot
9358  * assume here that they have done so.
9359  *
9360  * A function with a polymorphic argument could change behavior
9361  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
9362  * when the cast destination is polymorphic, we only avoid
9363  * revalidation if the input type has not changed at all. Given
9364  * just the core data types and operator classes, this requirement
9365  * prevents no would-be optimizations.
9366  *
9367  * If the cast converts from a base type to a domain thereon, then
9368  * that domain type must be the opcintype of the unique index.
9369  * Necessarily, the primary key column must then be of the domain
9370  * type. Since the constraint was previously valid, all values on
9371  * the foreign side necessarily exist on the primary side and in
9372  * turn conform to the domain. Consequently, we need not treat
9373  * domains specially here.
9374  *
9375  * Since we require that all collations share the same notion of
9376  * equality (which they do, because texteq reduces to bitwise
9377  * equality), we don't compare collation here.
9378  *
9379  * We need not directly consider the PK type. It's necessarily
9380  * binary coercible to the opcintype of the unique index column,
9381  * and ri_triggers.c will only deal with PK datums in terms of
9382  * that opcintype. Changing the opcintype also changes pfeqop.
9383  */
9384  old_check_ok = (new_pathtype == old_pathtype &&
9385  new_castfunc == old_castfunc &&
9386  (!IsPolymorphicType(pfeqop_right) ||
9387  new_fktype == old_fktype));
9388  }
9389 
9390  pfeqoperators[i] = pfeqop;
9391  ppeqoperators[i] = ppeqop;
9392  ffeqoperators[i] = ffeqop;
9393  }
9394 
9395  /*
9396  * Create all the constraint and trigger objects, recursing to partitions
9397  * as necessary. First handle the referenced side.
9398  */
9399  address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
9400  indexOid,
9401  InvalidOid, /* no parent constraint */
9402  numfks,
9403  pkattnum,
9404  fkattnum,
9405  pfeqoperators,
9406  ppeqoperators,
9407  ffeqoperators,
9408  numfkdelsetcols,
9409  fkdelsetcols,
9410  old_check_ok,
9412 
9413  /* Now handle the referencing side. */
9414  addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
9415  indexOid,
9416  address.objectId,
9417  numfks,
9418  pkattnum,
9419  fkattnum,
9420  pfeqoperators,
9421  ppeqoperators,
9422  ffeqoperators,
9423  numfkdelsetcols,
9424  fkdelsetcols,
9425  old_check_ok,
9426  lockmode,
9428 
9429  /*
9430  * Done. Close pk table, but keep lock until we've committed.
9431  */
9432  table_close(pkrel, NoLock);
9433 
9434  return address;
9435 }
signed short int16
Definition: c.h:429
bool IsSystemRelation(Relation relation)
Definition: catalog.c:75
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
bool allowSystemTableMods
Definition: globals.c:124
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:165
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2479
bool can_coerce_type(int nargs, const Oid *input_typeids, const Oid *target_typeids, CoercionContext ccontext)
Definition: parse_coerce.c:556
CoercionPathType
Definition: parse_coerce.h:25
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2329
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2327
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2328
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
static ListCell * list_head(const List *l)
Definition: pg_list.h:126
static void * list_nth(const List *list, int n)
Definition: pg_list.h:297
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:341
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
@ COERCION_IMPLICIT
Definition: primnodes.h:566
#define RelationIsPermanent(relation)
Definition: rel.h:615
TupleDesc oldDesc
Definition: tablecmds.c:163
List * pk_attrs
Definition: parsenodes.h:2378
List * fk_del_set_cols
Definition: parsenodes.h:2382
Oid old_pktable_oid
Definition: parsenodes.h:2384
List * old_conpfeqop
Definition: parsenodes.h:2383
RangeVar * pktable
Definition: parsenodes.h:2376
bool rd_islocaltemp
Definition: rel.h:60
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
@ CLAOID
Definition: syscache.h:48
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:83
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
Definition: tablecmds.c:11242
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:11480
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids)
Definition: tablecmds.c:11196
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:11509
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
Definition: tablecmds.c:11339
static void validateFkOnDeleteSetColumns(int numfks, const int16 *fkattnums, int numfksetcols, const int16 *fksetcolsattnums, List *fksetcols)
Definition: tablecmds.c:9443
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
#define strVal(v)
Definition: value.h:82

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

Referenced by ATExecAddConstraint().

◆ ATCheckPartitionsNotInUse()

static void ATCheckPartitionsNotInUse ( Relation  rel,
LOCKMODE  lockmode 
)
static

Definition at line 6376 of file tablecmds.c.

6377 {
6378  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6379  {
6380  List *inh;
6381  ListCell *cell;
6382 
6383  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6384  /* first element is the parent rel; must ignore it */
6385  for_each_from(cell, inh, 1)
6386  {
6387  Relation childrel;
6388 
6389  /* find_all_inheritors already got lock */
6390  childrel = table_open(lfirst_oid(cell), NoLock);
6391  CheckTableNotInUse(childrel, "ALTER TABLE");
6392  table_close(childrel, NoLock);
6393  }
6394  list_free(inh);
6395  }
6396 }
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:256
#define for_each_from(cell, lst, N)
Definition: pg_list.h:412

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

Referenced by ATPrepCmd().

◆ ATColumnChangeRequiresRewrite()

static bool ATColumnChangeRequiresRewrite ( Node expr,
AttrNumber  varattno 
)
static

Definition at line 12387 of file tablecmds.c.

12388 {
12389  Assert(expr != NULL);
12390 
12391  for (;;)
12392  {
12393  /* only one varno, so no need to check that */
12394  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
12395  return false;
12396  else if (IsA(expr, RelabelType))
12397  expr = (Node *) ((RelabelType *) expr)->arg;
12398  else if (IsA(expr, CoerceToDomain))
12399  {
12400  CoerceToDomain *d = (CoerceToDomain *) expr;
12401 
12403  return true;
12404  expr = (Node *) d->arg;
12405  }
12406  else if (IsA(expr, FuncExpr))
12407  {
12408  FuncExpr *f = (FuncExpr *) expr;
12409 
12410  switch (f->funcid)
12411  {
12412  case F_TIMESTAMPTZ_TIMESTAMP:
12413  case F_TIMESTAMP_TIMESTAMPTZ:
12415  return true;
12416  else
12417  expr = linitial(f->args);
12418  break;
12419  default:
12420  return true;
12421  }
12422  }
12423  else
12424  return true;
12425  }
12426 }
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:5532
void * arg
#define linitial(l)
Definition: pg_list.h:176
Oid funcid
Definition: primnodes.h:598
List * args
Definition: primnodes.h:606
Definition: primnodes.h:205
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1392

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

Referenced by ATPrepAlterColumnType().

◆ ATController()

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

Definition at line 4437 of file tablecmds.c.

4440 {
4441  List *wqueue = NIL;
4442  ListCell *lcmd;
4443 
4444  /* Phase 1: preliminary examination of commands, create work queue */
4445  foreach(lcmd, cmds)
4446  {
4447  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4448 
4449  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4450  }
4451 
4452  /* Close the relation, but keep lock until commit */
4453  relation_close(rel, NoLock);
4454 
4455  /* Phase 2: update system catalogs */
4456  ATRewriteCatalogs(&wqueue, lockmode, context);
4457 
4458  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4459  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4460 }
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4846
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4472
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5415

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

Referenced by AlterTable(), and AlterTableInternal().

◆ ATDetachCheckNoForeignKeyRefs()

static void ATDetachCheckNoForeignKeyRefs ( Relation  partition)
static

Definition at line 19223 of file tablecmds.c.

19224 {
19225  List *constraints;
19226  ListCell *cell;
19227 
19228  constraints = GetParentedForeignKeyRefs(partition);
19229 
19230  foreach(cell, constraints)
19231  {
19232  Oid constrOid = lfirst_oid(cell);
19233  HeapTuple tuple;
19234  Form_pg_constraint constrForm;
19235  Relation rel;
19236  Trigger trig = {0};
19237 
19238  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
19239  if (!HeapTupleIsValid(tuple))
19240  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
19241  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
19242 
19243  Assert(OidIsValid(constrForm->conparentid));
19244  Assert(constrForm->confrelid == RelationGetRelid(partition));
19245 
19246  /* prevent data changes into the referencing table until commit */
19247  rel = table_open(constrForm->conrelid, ShareLock);
19248 
19249  trig.tgoid = InvalidOid;
19250  trig.tgname = NameStr(constrForm->conname);
19252  trig.tgisinternal = true;
19253  trig.tgconstrrelid = RelationGetRelid(partition);
19254  trig.tgconstrindid = constrForm->conindid;
19255  trig.tgconstraint = constrForm->oid;
19256  trig.tgdeferrable = false;
19257  trig.tginitdeferred = false;
19258  /* we needn't fill in remaining fields */
19259 
19260  RI_PartitionRemove_Check(&trig, rel, partition);
19261 
19262  ReleaseSysCache(tuple);
19263 
19264  table_close(rel, NoLock);
19265  }
19266 }
#define ShareLock
Definition: lockdefs.h:40
FormData_pg_constraint * Form_pg_constraint
void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1648
char tgenabled
Definition: reltrigger.h:30
Oid tgoid
Definition: reltrigger.h:25
Oid tgconstrindid
Definition: reltrigger.h:34
Oid tgconstraint
Definition: reltrigger.h:35
Oid tgconstrrelid
Definition: reltrigger.h:33
char * tgname
Definition: reltrigger.h:27
bool tgdeferrable
Definition: reltrigger.h:36
bool tginitdeferred
Definition: reltrigger.h:37
bool tgisinternal
Definition: reltrigger.h:31
@ CONSTROID
Definition: syscache.h:53
static List * GetParentedForeignKeyRefs(Relation partition)
Definition: tablecmds.c:19170
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:149

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

Referenced by ATExecDetachPartition().

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 16903 of file tablecmds.c.

16905 {
16906  ListCell *cur_item;
16907 
16908  foreach(cur_item, on_commits)
16909  {
16910  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16911 
16912  if (!isCommit && oc->creating_subid == mySubid)
16913  {
16914  /* cur_item must be removed */
16916  pfree(oc);
16917  }
16918  else
16919  {
16920  /* cur_item must be preserved */
16921  if (oc->creating_subid == mySubid)
16922  oc->creating_subid = parentSubid;
16923  if (oc->deleting_subid == mySubid)
16924  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
16925  }
16926  }
16927 }
#define InvalidSubTransactionId
Definition: c.h:594
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:388
SubTransactionId creating_subid
Definition: tablecmds.c:122
SubTransactionId deleting_subid
Definition: tablecmds.c:123
static List * on_commits
Definition: tablecmds.c:126

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 16871 of file tablecmds.c.

16872 {
16873  ListCell *cur_item;
16874 
16875  foreach(cur_item, on_commits)
16876  {
16877  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16878 
16879  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
16881  {
16882  /* cur_item must be removed */
16884  pfree(oc);
16885  }
16886  else
16887  {
16888  /* cur_item must be preserved */
16891  }
16892  }
16893 }

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

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

◆ ATExecAddColumn()

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

Definition at line 6685 of file tablecmds.c.

6690 {
6691  Oid myrelid = RelationGetRelid(rel);
6692  ColumnDef *colDef = castNode(ColumnDef, (*cmd)->def);
6693  bool if_not_exists = (*cmd)->missing_ok;
6694  Relation pgclass,
6695  attrdesc;
6696  HeapTuple reltup;
6697  FormData_pg_attribute attribute;
6698  int newattnum;
6699  char relkind;
6700  HeapTuple typeTuple;
6701  Oid typeOid;
6702  int32 typmod;
6703  Oid collOid;
6704  Form_pg_type tform;
6705  Expr *defval;
6706  List *children;
6707  ListCell *child;
6708  AlterTableCmd *childcmd;
6709  AclResult aclresult;
6710  ObjectAddress address;
6711  TupleDesc tupdesc;
6712  FormData_pg_attribute *aattr[] = {&attribute};
6713 
6714  /* At top level, permission check was done in ATPrepCmd, else do it */
6715  if (recursing)
6716  ATSimplePermissions((*cmd)->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
6717 
6718  if (rel->rd_rel->relispartition && !recursing)
6719  ereport(ERROR,
6720  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6721  errmsg("cannot add column to a partition")));
6722 
6723  attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
6724 
6725  /*
6726  * Are we adding the column to a recursion child? If so, check whether to
6727  * merge with an existing definition for the column. If we do merge, we
6728  * must not recurse. Children will already have the column, and recursing
6729  * into them would mess up attinhcount.
6730  */
6731  if (colDef->inhcount > 0)
6732  {
6733  HeapTuple tuple;
6734 
6735  /* Does child already have a column by this name? */
6736  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
6737  if (HeapTupleIsValid(tuple))
6738  {
6739  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
6740  Oid ctypeId;
6741  int32 ctypmod;
6742  Oid ccollid;
6743 
6744  /* Child column must match on type, typmod, and collation */
6745  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
6746  if (ctypeId != childatt->atttypid ||
6747  ctypmod != childatt->atttypmod)
6748  ereport(ERROR,
6749  (errcode(ERRCODE_DATATYPE_MISMATCH),
6750  errmsg("child table \"%s\" has different type for column \"%s\"",
6751  RelationGetRelationName(rel), colDef->colname)));
6752  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
6753  if (ccollid != childatt->attcollation)
6754  ereport(ERROR,
6755  (errcode(ERRCODE_COLLATION_MISMATCH),
6756  errmsg("child table \"%s\" has different collation for column \"%s\"",
6757  RelationGetRelationName(rel), colDef->colname),
6758  errdetail("\"%s\" versus \"%s\"",
6759  get_collation_name(ccollid),
6760  get_collation_name(childatt->attcollation))));
6761 
6762  /* Bump the existing child att's inhcount */
6763  childatt->attinhcount++;
6764  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
6765 
6766  heap_freetuple(tuple);
6767 
6768  /* Inform the user about the merge */
6769  ereport(NOTICE,
6770  (errmsg("merging definition of column \"%s\" for child \"%s\"",
6771  colDef->colname, RelationGetRelationName(rel))));
6772 
6773  table_close(attrdesc, RowExclusiveLock);
6774  return InvalidObjectAddress;
6775  }
6776  }
6777 
6778  /* skip if the name already exists and if_not_exists is true */
6779  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
6780  {
6781  table_close(attrdesc, RowExclusiveLock);
6782  return InvalidObjectAddress;
6783  }
6784 
6785  /*
6786  * Okay, we need to add the column, so go ahead and do parse
6787  * transformation. This can result in queueing up, or even immediately
6788  * executing, subsidiary operations (such as creation of unique indexes);
6789  * so we mustn't do it until we have made the if_not_exists check.
6790  *
6791  * When recursing, the command was already transformed and we needn't do
6792  * so again. Also, if context isn't given we can't transform. (That
6793  * currently happens only for AT_AddColumnToView; we expect that view.c
6794  * passed us a ColumnDef that doesn't need work.)
6795  */
6796  if (context != NULL && !recursing)
6797  {
6798  *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
6799  cur_pass, context);
6800  Assert(*cmd != NULL);
6801  colDef = castNode(ColumnDef, (*cmd)->def);
6802  }
6803 
6804  /*
6805  * Cannot add identity column if table has children, because identity does
6806  * not inherit. (Adding column and identity separately will work.)
6807  */
6808  if (colDef->identity &&
6809  recurse &&
6810  find_inheritance_children(myrelid, NoLock) != NIL)
6811  ereport(ERROR,
6812  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6813  errmsg("cannot recursively add identity column to table that has child tables")));
6814 
6815  pgclass = table_open(RelationRelationId, RowExclusiveLock);
6816 
6817  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
6818  if (!HeapTupleIsValid(reltup))
6819  elog(ERROR, "cache lookup failed for relation %u", myrelid);
6820  relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
6821 
6822  /* Determine the new attribute's number */
6823  newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
6824  if (newattnum > MaxHeapAttributeNumber)
6825  ereport(ERROR,
6826  (errcode(ERRCODE_TOO_MANY_COLUMNS),
6827  errmsg("tables can have at most %d columns",
6829 
6830  typeTuple = typenameType(NULL, colDef->typeName, &typmod);
6831  tform = (Form_pg_type) GETSTRUCT(typeTuple);
6832  typeOid = tform->oid;
6833 
6834  aclresult = object_aclcheck(TypeRelationId, typeOid, GetUserId(), ACL_USAGE);
6835  if (aclresult != ACLCHECK_OK)
6836  aclcheck_error_type(aclresult, typeOid);
6837 
6838  collOid = GetColumnDefCollation(NULL, colDef, typeOid);
6839 
6840  /* make sure datatype is legal for a column */
6841  CheckAttributeType(colDef->colname, typeOid, collOid,
6842  list_make1_oid(rel->rd_rel->reltype),
6843  0);
6844 
6845  /*
6846  * Construct new attribute's pg_attribute entry. (Variable-length fields
6847  * are handled by InsertPgAttributeTuples().)
6848  */
6849  attribute.attrelid = myrelid;
6850  namestrcpy(&(attribute.attname), colDef->colname);
6851  attribute.atttypid = typeOid;
6852  attribute.attstattarget = (newattnum > 0) ? -1 : 0;
6853  attribute.attlen = tform->typlen;
6854  attribute.attnum = newattnum;
6855  attribute.attndims = list_length(colDef->typeName->arrayBounds);
6856  attribute.atttypmod = typmod;
6857  attribute.attbyval = tform->typbyval;
6858  attribute.attalign = tform->typalign;
6859  if (colDef->storage_name)
6860  attribute.attstorage = GetAttributeStorage(typeOid, colDef->storage_name);
6861  else
6862  attribute.attstorage = tform->typstorage;
6863  attribute.attcompression = GetAttributeCompression(typeOid,
6864  colDef->compression);
6865  attribute.attnotnull = colDef->is_not_null;
6866  attribute.atthasdef = false;
6867  attribute.atthasmissing = false;
6868  attribute.attidentity = colDef->identity;
6869  attribute.attgenerated = colDef->generated;
6870  attribute.attisdropped = false;
6871  attribute.attislocal = colDef->is_local;
6872  attribute.attinhcount = colDef->inhcount;
6873  attribute.attcollation = collOid;
6874 
6875  ReleaseSysCache(typeTuple);
6876 
6877  tupdesc = CreateTupleDesc(lengthof(aattr), (FormData_pg_attribute **) &aattr);
6878 
6879  InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
6880 
6881  table_close(attrdesc, RowExclusiveLock);
6882 
6883  /*
6884  * Update pg_class tuple as appropriate
6885  */
6886  ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
6887 
6888  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
6889 
6890  heap_freetuple(reltup);
6891 
6892  /* Post creation hook for new attribute */
6893  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
6894 
6895  table_close(pgclass, RowExclusiveLock);
6896 
6897  /* Make the attribute's catalog entry visible */
6899 
6900  /*
6901  * Store the DEFAULT, if any, in the catalogs
6902  */
6903  if (colDef->raw_default)
6904  {
6905  RawColumnDefault *rawEnt;
6906 
6907  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
6908  rawEnt->attnum = attribute.attnum;
6909  rawEnt->raw_default = copyObject(colDef->raw_default);
6910 
6911  /*
6912  * Attempt to skip a complete table rewrite by storing the specified
6913  * DEFAULT value outside of the heap. This may be disabled inside
6914  * AddRelationNewConstraints if the optimization cannot be applied.
6915  */
6916  rawEnt->missingMode = (!colDef->generated);
6917 
6918  rawEnt->generated = colDef->generated;
6919 
6920  /*
6921  * This function is intended for CREATE TABLE, so it processes a
6922  * _list_ of defaults, but we just do one.
6923  */
6925  false, true, false, NULL);
6926 
6927  /* Make the additional catalog changes visible */
6929 
6930  /*
6931  * Did the request for a missing value work? If not we'll have to do a
6932  * rewrite
6933  */
6934  if (!rawEnt->missingMode)
6936  }
6937 
6938  /*
6939  * Tell Phase 3 to fill in the default expression, if there is one.
6940  *
6941  * If there is no default, Phase 3 doesn't have to do anything, because
6942  * that effectively means that the default is NULL. The heap tuple access
6943  * routines always check for attnum > # of attributes in tuple, and return
6944  * NULL if so, so without any modification of the tuple data we will get
6945  * the effect of NULL values in the new column.
6946  *
6947  * An exception occurs when the new column is of a domain type: the domain
6948  * might have a NOT NULL constraint, or a check constraint that indirectly
6949  * rejects nulls. If there are any domain constraints then we construct
6950  * an explicit NULL default value that will be passed through
6951  * CoerceToDomain processing. (This is a tad inefficient, since it causes
6952  * rewriting the table which we really don't have to do, but the present
6953  * design of domain processing doesn't offer any simple way of checking
6954  * the constraints more directly.)
6955  *
6956  * Note: we use build_column_default, and not just the cooked default
6957  * returned by AddRelationNewConstraints, so that the right thing happens
6958  * when a datatype's default applies.
6959  *
6960  * Note: it might seem that this should happen at the end of Phase 2, so
6961  * that the effects of subsequent subcommands can be taken into account.
6962  * It's intentional that we do it now, though. The new column should be
6963  * filled according to what is said in the ADD COLUMN subcommand, so that
6964  * the effects are the same as if this subcommand had been run by itself
6965  * and the later subcommands had been issued in new ALTER TABLE commands.
6966  *
6967  * We can skip this entirely for relations without storage, since Phase 3
6968  * is certainly not going to touch them. System attributes don't have
6969  * interesting defaults, either.
6970  */
6971  if (RELKIND_HAS_STORAGE(relkind) && attribute.attnum > 0)
6972  {
6973  /*
6974  * For an identity column, we can't use build_column_default(),
6975  * because the sequence ownership isn't set yet. So do it manually.
6976  */
6977  if (colDef->identity)
6978  {
6980 
6981  nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
6982  nve->typeId = typeOid;
6983 
6984  defval = (Expr *) nve;
6985 
6986  /* must do a rewrite for identity columns */
6988  }
6989  else
6990  defval = (Expr *) build_column_default(rel, attribute.attnum);
6991 
6992  if (!defval && DomainHasConstraints(typeOid))
6993  {
6994  Oid baseTypeId;
6995  int32 baseTypeMod;
6996  Oid baseTypeColl;
6997 
6998  baseTypeMod = typmod;
6999  baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
7000  baseTypeColl = get_typcollation(baseTypeId);
7001  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
7002  defval = (Expr *) coerce_to_target_type(NULL,
7003  (Node *) defval,
7004  baseTypeId,
7005  typeOid,
7006  typmod,
7009  -1);
7010  if (defval == NULL) /* should not happen */
7011  elog(ERROR, "failed to coerce base type to domain");
7012  }
7013 
7014  if (defval)
7015  {
7017 
7019  newval->attnum = attribute.attnum;
7020  newval->expr = expression_planner(defval);
7021  newval->is_generated = (colDef->generated != '\0');
7022 
7023  tab->newvals = lappend(tab->newvals, newval);
7024  }
7025 
7026  if (DomainHasConstraints(typeOid))
7028 
7029  if (!TupleDescAttr(rel->rd_att, attribute.attnum - 1)->atthasmissing)
7030  {
7031  /*
7032  * If the new column is NOT NULL, and there is no missing value,
7033  * tell Phase 3 it needs to check for NULLs.
7034  */
7035  tab->verify_new_notnull |= colDef->is_not_null;
7036  }
7037  }
7038 
7039  /*
7040  * Add needed dependency entries for the new column.
7041  */
7042  add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
7043  add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
7044 
7045  /*
7046  * Propagate to children as appropriate. Unlike most other ALTER
7047  * routines, we have to do this one level of recursion at a time; we can't
7048  * use find_all_inheritors to do it in one pass.
7049  */
7050  children =
7052 
7053  /*
7054  * If we are told not to recurse, there had better not be any child
7055  * tables; else the addition would put them out of step.
7056  */
7057  if (children && !recurse)
7058  ereport(ERROR,
7059  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7060  errmsg("column must be added to child tables too")));
7061 
7062  /* Children should see column as singly inherited */
7063  if (!recursing)
7064  {
7065  childcmd = copyObject(*cmd);
7066  colDef = castNode(ColumnDef, childcmd->def);
7067  colDef->inhcount = 1;
7068  colDef->is_local = false;
7069  }
7070  else
7071  childcmd = *cmd; /* no need to copy again */
7072 
7073  foreach(child, children)
7074  {
7075  Oid childrelid = lfirst_oid(child);
7076  Relation childrel;
7077  AlteredTableInfo *childtab;
7078 
7079  /* find_inheritance_children already got lock */
7080  childrel = table_open(childrelid, NoLock);
7081  CheckTableNotInUse(childrel, "ALTER TABLE");
7082 
7083  /* Find or create work queue entry for this table */
7084  childtab = ATGetQueueEntry(wqueue, childrel);
7085 
7086  /* Recurse to child; return value is ignored */
7087  ATExecAddColumn(wqueue, childtab, childrel,
7088  &childcmd, recurse, true,
7089  lockmode, cur_pass, context);
7090 
7091  table_close(childrel, NoLock);
7092  }
7093 
7094  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
7095  return address;
7096 }
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3804
#define lengthof(array)
Definition: c.h:724
#define AT_REWRITE_DEFAULT_VAL
Definition: event_trigger.h:33
#define newval
void InsertPgAttributeTuples(Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, Datum *attoptions, CatalogIndexState indstate)
Definition: heap.c:697
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
Definition: heap.c:547
#define MaxHeapAttributeNumber
Definition: htup_details.h:47
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3014
char * get_collation_name(Oid colloid)
Definition: lsyscache.c:1061
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2496
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:337
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:79
#define castNode(_type_, nodeptr)
Definition: nodes.h:186
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, Oid *typeid_p, int32 *typmod_p)
Definition: parse_type.c:310
Oid GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid)
Definition: parse_type.c:540
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:264
#define ACL_USAGE
Definition: parsenodes.h:91
FormData_pg_attribute
Definition: pg_attribute.h:191
#define list_make1_oid(x1)
Definition: pg_list.h:240
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
Expr * expression_planner(Expr *expr)
Definition: planner.c:6147
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:588
@ COERCION_ASSIGNMENT
Definition: primnodes.h:567
Node * build_column_default(Relation rel, int attrno)
bool verify_new_notnull
Definition: tablecmds.c:180
bool is_not_null
Definition: parsenodes.h:693
char identity
Definition: parsenodes.h:699
RangeVar * identitySequence
Definition: parsenodes.h:700
char * storage_name
Definition: parsenodes.h:696
int inhcount
Definition: parsenodes.h:691
char * colname
Definition: parsenodes.h:688
TypeName * typeName
Definition: parsenodes.h:689
char generated
Definition: parsenodes.h:702
Node * raw_default
Definition: parsenodes.h:697
bool is_local
Definition: parsenodes.h:692
char * compression
Definition: parsenodes.h:690
Node * raw_default
Definition: heap.h:30
AttrNumber attnum
Definition: heap.h:29
char generated
Definition: heap.h:32
bool missingMode
Definition: heap.h:31
TupleDesc rd_att
Definition: rel.h:111
List * arrayBounds
Definition: parsenodes.h:239
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:1337
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
Definition: tablecmds.c:7156
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:6685
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:7174
static AlterTableCmd * ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5280
static char GetAttributeCompression(Oid atttypid, char *compression)
Definition: tablecmds.c:19272
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:7103
static char GetAttributeStorage(Oid atttypid, const char *storagemode)
Definition: tablecmds.c:19310
TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs)
Definition: tupdesc.c:90

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

Referenced by ATExecCmd().

◆ ATExecAddConstraint()

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

Definition at line 8766 of file tablecmds.c.

8769 {
8771 
8772  Assert(IsA(newConstraint, Constraint));
8773 
8774  /*
8775  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
8776  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
8777  * switch anyway to make it easier to add more code later.
8778  */
8779  switch (newConstraint->contype)
8780  {
8781  case CONSTR_CHECK:
8782  address =
8783  ATAddCheckConstraint(wqueue, tab, rel,
8784  newConstraint, recurse, false, is_readd,
8785  lockmode);
8786  break;
8787 
8788  case CONSTR_FOREIGN:
8789 
8790  /*
8791  * Assign or validate constraint name
8792  */
8793  if (newConstraint->conname)
8794  {
8796  RelationGetRelid(rel),
8797  newConstraint->conname))
8798  ereport(ERROR,
8800  errmsg("constraint \"%s\" for relation \"%s\" already exists",
8801  newConstraint->conname,
8802  RelationGetRelationName(rel))));
8803  }
8804  else
8805  newConstraint->conname =
8808  "fkey",
8809  RelationGetNamespace(rel),
8810  NIL);
8811 
8812  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
8813  newConstraint,
8814  recurse, false,
8815  lockmode);
8816  break;
8817 
8818  default:
8819  elog(ERROR, "unrecognized constraint type: %d",
8820  (int) newConstraint->contype);
8821  }
8822 
8823  return address;
8824 }
@ CONSTR_CHECK
Definition: parsenodes.h:2313
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:9018

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

Referenced by ATExecCmd().

◆ ATExecAddIdentity()

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

Definition at line 7686 of file tablecmds.c.

7688 {
7689  Relation attrelation;
7690  HeapTuple tuple;
7691  Form_pg_attribute attTup;
7693  ObjectAddress address;
7694  ColumnDef *cdef = castNode(ColumnDef, def);
7695 
7696  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7697 
7698  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7699  if (!HeapTupleIsValid(tuple))
7700  ereport(ERROR,
7701  (errcode(ERRCODE_UNDEFINED_COLUMN),
7702  errmsg("column \"%s\" of relation \"%s\" does not exist",
7703  colName, RelationGetRelationName(rel))));
7704  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7705  attnum = attTup->attnum;
7706 
7707  /* Can't alter a system attribute */
7708  if (attnum <= 0)
7709  ereport(ERROR,
7710  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7711  errmsg("cannot alter system column \"%s\"",
7712  colName)));
7713 
7714  /*
7715  * Creating a column as identity implies NOT NULL, so adding the identity
7716  * to an existing column that is not NOT NULL would create a state that
7717  * cannot be reproduced without contortions.
7718  */
7719  if (!attTup->attnotnull)
7720  ereport(ERROR,
7721  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7722  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
7723  colName, RelationGetRelationName(rel))));
7724 
7725  if (attTup->attidentity)
7726  ereport(ERROR,
7727  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7728  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
7729  colName, RelationGetRelationName(rel))));
7730 
7731  if (attTup->atthasdef)
7732  ereport(ERROR,
7733  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7734  errmsg("column \"%s\" of relation \"%s\" already has a default value",
7735  colName, RelationGetRelationName(rel))));
7736 
7737  attTup->attidentity = cdef->identity;
7738  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7739 
7740  InvokeObjectPostAlterHook(RelationRelationId,
7741  RelationGetRelid(rel),
7742  attTup->attnum);
7743  ObjectAddressSubSet(address, RelationRelationId,
7744  RelationGetRelid(rel), attnum);
7745  heap_freetuple(tuple);
7746 
7747  table_close(attrelation, RowExclusiveLock);
7748 
7749  return address;
7750 }

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

Referenced by ATExecCmd().

◆ ATExecAddIndex()

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

Definition at line 8591 of file tablecmds.c.

8593 {
8594  bool check_rights;
8595  bool skip_build;
8596  bool quiet;
8597  ObjectAddress address;
8598 
8599  Assert(IsA(stmt, IndexStmt));
8600  Assert(!stmt->concurrent);
8601 
8602  /* The IndexStmt has already been through transformIndexStmt */
8603  Assert(stmt->transformed);
8604 
8605  /* suppress schema rights check when rebuilding existing index */
8606  check_rights = !is_rebuild;
8607  /* skip index build if phase 3 will do it or we're reusing an old one */
8608  skip_build = tab->rewrite > 0 || RelFileNumberIsValid(stmt->oldNumber);
8609  /* suppress notices when rebuilding existing index */
8610  quiet = is_rebuild;
8611 
8612  address = DefineIndex(RelationGetRelid(rel),
8613  stmt,
8614  InvalidOid, /* no predefined OID */
8615  InvalidOid, /* no parent index */
8616  InvalidOid, /* no parent constraint */
8617  true, /* is_alter_table */
8618  check_rights,
8619  false, /* check_not_in_use - we did it already */
8620  skip_build,
8621  quiet);
8622 
8623  /*
8624  * If TryReuseIndex() stashed a relfilenumber for us, we used it for the
8625  * new index instead of building from scratch. Restore associated fields.
8626  * This may store InvalidSubTransactionId in both fields, in which case
8627  * relcache.c will assume it can rebuild the relcache entry. Hence, do
8628  * this after the CCI that made catalog rows visible to any rebuild. The
8629  * DROP of the old edition of this index will have scheduled the storage
8630  * for deletion at commit, so cancel that pending deletion.
8631  */
8632  if (RelFileNumberIsValid(stmt->oldNumber))
8633  {
8634  Relation irel = index_open(address.objectId, NoLock);
8635 
8636  irel->rd_createSubid = stmt->oldCreateSubid;
8638  RelationPreserveStorage(irel->rd_locator, true);
8639  index_close(irel, NoLock);
8640  }
8641 
8642  return address;
8643 }
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
ObjectAddress DefineIndex(Oid 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:524
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
void RelationPreserveStorage(RelFileLocator rlocator, bool atCommit)
Definition: storage.c:250
SubTransactionId oldFirstRelfilelocatorSubid
Definition: parsenodes.h:2982
bool transformed
Definition: parsenodes.h:2990
SubTransactionId oldCreateSubid
Definition: parsenodes.h:2981
bool concurrent
Definition: parsenodes.h:2991
RelFileNumber oldNumber
Definition: parsenodes.h:2980
SubTransactionId rd_firstRelfilelocatorSubid
Definition: rel.h:105
SubTransactionId rd_createSubid
Definition: rel.h:102
RelFileLocator rd_locator
Definition: rel.h:56

References Assert(), IndexStmt::concurrent, DefineIndex(), index_close(), index_open(), InvalidOid, IsA, NoLock, ObjectAddress::objectId, IndexStmt::oldCreateSubid, IndexStmt::oldFirstRelfilelocatorSubid, IndexStmt::oldNumber, RelationData::rd_createSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_locator, RelationGetRelid, RelationPreserveStorage(), RelFileNumberIsValid, AlteredTableInfo::rewrite, and IndexStmt::transformed.

Referenced by ATExecCmd().

◆ ATExecAddIndexConstraint()

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

Definition at line 8674 of file tablecmds.c.

8676 {
8677  Oid index_oid = stmt->indexOid;
8678  Relation indexRel;
8679  char *indexName;
8680  IndexInfo *indexInfo;
8681  char *constraintName;
8682  char constraintType;
8683  ObjectAddress address;
8684  bits16 flags;
8685 
8686  Assert(IsA(stmt, IndexStmt));
8687  Assert(OidIsValid(index_oid));
8688  Assert(stmt->isconstraint);
8689 
8690  /*
8691  * Doing this on partitioned tables is not a simple feature to implement,
8692  * so let's punt for now.
8693  */
8694  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8695  ereport(ERROR,
8696  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8697  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
8698 
8699  indexRel = index_open(index_oid, AccessShareLock);
8700 
8701  indexName = pstrdup(RelationGetRelationName(indexRel));
8702 
8703  indexInfo = BuildIndexInfo(indexRel);
8704 
8705  /* this should have been checked at parse time */
8706  if (!indexInfo->ii_Unique)
8707  elog(ERROR, "index \"%s\" is not unique", indexName);
8708 
8709  /*
8710  * Determine name to assign to constraint. We require a constraint to
8711  * have the same name as the underlying index; therefore, use the index's
8712  * existing name as the default constraint name, and if the user
8713  * explicitly gives some other name for the constraint, rename the index
8714  * to match.
8715  */
8716  constraintName = stmt->idxname;
8717  if (constraintName == NULL)
8718  constraintName = indexName;
8719  else if (strcmp(constraintName, indexName) != 0)
8720  {
8721  ereport(NOTICE,
8722  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
8723  indexName, constraintName)));
8724  RenameRelationInternal(index_oid, constraintName, false, true);
8725  }
8726 
8727  /* Extra checks needed if making primary key */
8728  if (stmt->primary)
8729  index_check_primary_key(rel, indexInfo, true, stmt);
8730 
8731  /* Note we currently don't support EXCLUSION constraints here */
8732  if (stmt->primary)
8733  constraintType = CONSTRAINT_PRIMARY;
8734  else
8735  constraintType = CONSTRAINT_UNIQUE;
8736 
8737  /* Create the catalog entries for the constraint */
8743 
8744  address = index_constraint_create(rel,
8745  index_oid,
8746  InvalidOid,
8747  indexInfo,
8748  constraintName,
8749  constraintType,
8750  flags,
8752  false); /* is_internal */
8753 
8754  index_close(indexRel, NoLock);
8755 
8756  return address;
8757 }
uint16 bits16
Definition: c.h:450
ObjectAddress index_constraint_create(Relation heapRelation, Oid indexRelationId, Oid parentConstraintId, IndexInfo *indexInfo, const char *constraintName, char constraintType, bits16 constr_flags, bool allow_system_table_mods, bool is_internal)
Definition: index.c:1897
void index_check_primary_key(Relation heapRel, IndexInfo *indexInfo, bool is_alter_table, IndexStmt *stmt)
Definition: index.c:206
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2420
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:92
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:93
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:90
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition: index.h:89
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:91
char * pstrdup(const char *in)
Definition: mcxt.c:1483
bool ii_Unique
Definition: execnodes.h:190
bool deferrable
Definition: parsenodes.h:2988
Oid indexOid
Definition: parsenodes.h:2979
bool initdeferred
Definition: parsenodes.h:2989
bool isconstraint
Definition: parsenodes.h:2987
char * idxname
Definition: parsenodes.h:2968
bool primary
Definition: parsenodes.h:2986
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3861

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

◆ ATExecAddInherit()

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

Definition at line 14785 of file tablecmds.c.

14786 {
14787  Relation parent_rel;
14788  List *children;
14789  ObjectAddress address;
14790  const char *trigger_name;
14791 
14792  /*
14793  * A self-exclusive lock is needed here. See the similar case in
14794  * MergeAttributes() for a full explanation.
14795  */
14796  parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
14797 
14798  /*
14799  * Must be owner of both parent and child -- child was checked by
14800  * ATSimplePermissions call in ATPrepCmd
14801  */
14803 
14804  /* Permanent rels cannot inherit from temporary ones */
14805  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
14806  child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
14807  ereport(ERROR,
14808  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14809  errmsg("cannot inherit from temporary relation \"%s\"",
14810  RelationGetRelationName(parent_rel))));
14811 
14812  /* If parent rel is temp, it must belong to this session */
14813  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
14814  !parent_rel->rd_islocaltemp)
14815  ereport(ERROR,
14816  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14817  errmsg("cannot inherit from temporary relation of another session")));
14818 
14819  /* Ditto for the child */
14820  if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
14821  !child_rel->rd_islocaltemp)
14822  ereport(ERROR,
14823  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14824  errmsg("cannot inherit to temporary relation of another session")));
14825 
14826  /* Prevent partitioned tables from becoming inheritance parents */
14827  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14828  ereport(ERROR,
14829  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14830  errmsg("cannot inherit from partitioned table \"%s\"",
14831  parent->relname)));
14832 
14833  /* Likewise for partitions */
14834  if (parent_rel->rd_rel->relispartition)
14835  ereport(ERROR,
14836  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14837  errmsg("cannot inherit from a partition")));
14838 
14839  /*
14840  * Prevent circularity by seeing if proposed parent inherits from child.
14841  * (In particular, this disallows making a rel inherit from itself.)
14842  *
14843  * This is not completely bulletproof because of race conditions: in
14844  * multi-level inheritance trees, someone else could concurrently be
14845  * making another inheritance link that closes the loop but does not join
14846  * either of the rels we have locked. Preventing that seems to require
14847  * exclusive locks on the entire inheritance tree, which is a cure worse
14848  * than the disease. find_all_inheritors() will cope with circularity
14849  * anyway, so don't sweat it too much.
14850  *
14851  * We use weakest lock we can on child's children, namely AccessShareLock.
14852  */
14853  children = find_all_inheritors(RelationGetRelid(child_rel),
14854  AccessShareLock, NULL);
14855 
14856  if (list_member_oid(children, RelationGetRelid(parent_rel)))
14857  ereport(ERROR,
14858  (errcode(ERRCODE_DUPLICATE_TABLE),
14859  errmsg("circular inheritance not allowed"),
14860  errdetail("\"%s\" is already a child of \"%s\".",
14861  parent->relname,
14862  RelationGetRelationName(child_rel))));
14863 
14864  /*
14865  * If child_rel has row-level triggers with transition tables, we
14866  * currently don't allow it to become an inheritance child. See also
14867  * prohibitions in ATExecAttachPartition() and CreateTrigger().
14868  */
14869  trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
14870  if (trigger_name != NULL)
14871  ereport(ERROR,
14872  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14873  errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
14874  trigger_name, RelationGetRelationName(child_rel)),
14875  errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
14876 
14877  /* OK to create inheritance */
14878  CreateInheritance(child_rel, parent_rel);
14879 
14880  ObjectAddressSet(address, RelationRelationId,
14881  RelationGetRelid(parent_rel));
14882 
14883  /* keep our lock on the parent relation until commit */
14884  table_close(parent_rel, NoLock);
14885 
14886  return address;
14887 }
TriggerDesc * trigdesc
Definition: rel.h:116
static void CreateInheritance(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:14897
const char * FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc)
Definition: trigger.c:2277

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

Referenced by ATExecCmd().

◆ ATExecAddOf()

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

Definition at line 15669 of file tablecmds.c.

15670 {
15671  Oid relid = RelationGetRelid(rel);
15672  Type typetuple;
15673  Form_pg_type typeform;
15674  Oid typeid;
15675  Relation inheritsRelation,
15676  relationRelation;
15677  SysScanDesc scan;
15678  ScanKeyData key;
15679  AttrNumber table_attno,
15680  type_attno;
15681  TupleDesc typeTupleDesc,
15682  tableTupleDesc;
15683  ObjectAddress tableobj,
15684  typeobj;
15685  HeapTuple classtuple;
15686 
15687  /* Validate the type. */
15688  typetuple = typenameType(NULL, ofTypename, NULL);
15689  check_of_type(typetuple);
15690  typeform = (Form_pg_type) GETSTRUCT(typetuple);
15691  typeid = typeform->oid;
15692 
15693  /* Fail if the table has any inheritance parents. */
15694  inheritsRelation = table_open(InheritsRelationId, AccessShareLock);
15695  ScanKeyInit(&key,
15696  Anum_pg_inherits_inhrelid,
15697  BTEqualStrategyNumber, F_OIDEQ,
15698  ObjectIdGetDatum(relid));
15699  scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
15700  true, NULL, 1, &key);
15702  ereport(ERROR,
15703  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15704  errmsg("typed tables cannot inherit")));
15705  systable_endscan(scan);
15706  table_close(inheritsRelation, AccessShareLock);
15707 
15708  /*
15709  * Check the tuple descriptors for compatibility. Unlike inheritance, we
15710  * require that the order also match. However, attnotnull need not match.
15711  */
15712  typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
15713  tableTupleDesc = RelationGetDescr(rel);
15714  table_attno = 1;
15715  for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
15716  {
15717  Form_pg_attribute type_attr,
15718  table_attr;
15719  const char *type_attname,
15720  *table_attname;
15721 
15722  /* Get the next non-dropped type attribute. */
15723  type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
15724  if (type_attr->attisdropped)
15725  continue;
15726  type_attname = NameStr(type_attr->attname);
15727 
15728  /* Get the next non-dropped table attribute. */
15729  do
15730  {
15731  if (table_attno > tableTupleDesc->natts)
15732  ereport(ERROR,
15733  (errcode(ERRCODE_DATATYPE_MISMATCH),
15734  errmsg("table is missing column \"%s\"",
15735  type_attname)));
15736  table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
15737  table_attno++;
15738  } while (table_attr->attisdropped);
15739  table_attname = NameStr(table_attr->attname);
15740 
15741  /* Compare name. */
15742  if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
15743  ereport(ERROR,
15744  (errcode(ERRCODE_DATATYPE_MISMATCH),
15745  errmsg("table has column \"%s\" where type requires \"%s\"",
15746  table_attname, type_attname)));
15747 
15748  /* Compare type. */
15749  if (table_attr->atttypid != type_attr->atttypid ||
15750  table_attr->atttypmod != type_attr->atttypmod ||
15751  table_attr->attcollation != type_attr->attcollation)
15752  ereport(ERROR,
15753  (errcode(ERRCODE_DATATYPE_MISMATCH),
15754  errmsg("table \"%s\" has different type for column \"%s\"",
15755  RelationGetRelationName(rel), type_attname)));
15756  }
15757  ReleaseTupleDesc(typeTupleDesc);
15758 
15759  /* Any remaining columns at the end of the table had better be dropped. */
15760  for (; table_attno <= tableTupleDesc->natts; table_attno++)
15761  {
15762  Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
15763  table_attno - 1);
15764 
15765  if (!table_attr->attisdropped)
15766  ereport(ERROR,
15767  (errcode(ERRCODE_DATATYPE_MISMATCH),
15768  errmsg("table has extra column \"%s\"",
15769  NameStr(table_attr->attname))));
15770  }
15771 
15772  /* If the table was already typed, drop the existing dependency. */
15773  if (rel->rd_rel->reloftype)
15774  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
15776 
15777  /* Record a dependency on the new type. */
15778  tableobj.classId = RelationRelationId;
15779  tableobj.objectId = relid;
15780  tableobj.objectSubId = 0;
15781  typeobj.classId = TypeRelationId;
15782  typeobj.objectId = typeid;
15783  typeobj.objectSubId = 0;
15784  recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
15785 
15786  /* Update pg_class.reloftype */
15787  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
15788  classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
15789  if (!HeapTupleIsValid(classtuple))
15790  elog(ERROR, "cache lookup failed for relation %u", relid);
15791  ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
15792  CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
15793 
15794  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
15795 
15796  heap_freetuple(classtuple);
15797  table_close(relationRelation, RowExclusiveLock);
15798 
15799  ReleaseSysCache(typetuple);
15800 
15801  return typeobj;
15802 }
#define NAMEDATALEN
static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
Definition: tablecmds.c:15617
void check_of_type(HeapTuple typetuple)
Definition: tablecmds.c:6618
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1824

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

Referenced by ATExecCmd().

◆ ATExecAddStatistics()

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

Definition at line 8653 of file tablecmds.c.

8655 {
8656  ObjectAddress address;
8657 
8658  Assert(IsA(stmt, CreateStatsStmt));
8659 
8660  /* The CreateStatsStmt has already been through transformStatsStmt */
8661  Assert(stmt->transformed);
8662 
8663  address = CreateStatistics(stmt);
8664 
8665  return address;
8666 }
ObjectAddress CreateStatistics(CreateStatsStmt *stmt)
Definition: statscmds.c:65

References Assert(), CreateStatistics(), IsA, and CreateStatsStmt::transformed.

Referenced by ATExecCmd().

◆ ATExecAlterColumnGenericOptions()

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

Definition at line 13596 of file tablecmds.c.

13600 {
13601  Relation ftrel;
13602  Relation attrel;
1360