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_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 indoid, AlteredTableInfo *tab)
 
static void ATPostAlterTypeCleanup (List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
 
static void ATPostAlterTypeParse (Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, List **wqueue, LOCKMODE lockmode, bool rewrite)
 
static void RebuildConstraintComment (AlteredTableInfo *tab, int pass, Oid objid, Relation rel, List *domname, const char *conname)
 
static void TryReuseIndex (Oid oldId, IndexStmt *stmt)
 
static void TryReuseForeignKey (Oid oldId, Constraint *con)
 
static ObjectAddress ATExecAlterColumnGenericOptions (Relation rel, const char *colName, List *options, LOCKMODE lockmode)
 
static void change_owner_fix_column_acls (Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
 
static void change_owner_recurse_to_sequences (Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
 
static ObjectAddress ATExecClusterOn (Relation rel, const char *indexName, LOCKMODE lockmode)
 
static void ATExecDropCluster (Relation rel, LOCKMODE lockmode)
 
static 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, LOCKMODE lockmode)
 
static void ATExecEnableDisableRule (Relation rel, const char *rulename, char fires_when, LOCKMODE lockmode)
 
static void ATPrepAddInherit (Relation child_rel)
 
static ObjectAddress ATExecAddInherit (Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
 
static ObjectAddress ATExecDropInherit (Relation rel, RangeVar *parent, LOCKMODE lockmode)
 
static void drop_parent_dependency (Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
 
static ObjectAddress ATExecAddOf (Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
 
static void ATExecDropOf (Relation rel, LOCKMODE lockmode)
 
static void ATExecReplicaIdentity (Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
 
static void ATExecGenericOptions (Relation rel, List *options)
 
static void ATExecSetRowSecurity (Relation rel, bool rls)
 
static void ATExecForceNoForceRowSecurity (Relation rel, bool force_rls)
 
static ObjectAddress ATExecSetCompression (AlteredTableInfo *tab, Relation rel, const char *column, Node *newValue, LOCKMODE lockmode)
 
static void index_copy_data (Relation rel, RelFileNode newrnode)
 
static const char * storage_name (char c)
 
static void RangeVarCallbackForDropRelation (const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
 
static void RangeVarCallbackForAlterRelation (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
static PartitionSpectransformPartitionSpec (Relation rel, PartitionSpec *partspec, char *strategy)
 
static void ComputePartitionAttrs (ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, char strategy)
 
static void CreateInheritance (Relation child_rel, Relation parent_rel)
 
static void RemoveInheritance (Relation child_rel, Relation parent_rel, bool allow_detached)
 
static ObjectAddress ATExecAttachPartition (List **wqueue, Relation rel, PartitionCmd *cmd, AlterTableUtilityContext *context)
 
static void AttachPartitionEnsureIndexes (Relation rel, Relation attachrel)
 
static void QueuePartitionConstraintValidation (List **wqueue, Relation scanrel, List *partConstraint, bool validate_default)
 
static void CloneRowTriggersToPartition (Relation parent, Relation partition)
 
static void DetachAddConstraintIfNeeded (List **wqueue, Relation partRel)
 
static void DropClonedTriggersFromPartition (Oid partitionId)
 
static ObjectAddress ATExecDetachPartition (List **wqueue, AlteredTableInfo *tab, Relation rel, RangeVar *name, bool concurrent)
 
static void DetachPartitionFinalize (Relation rel, Relation partRel, bool concurrent, Oid defaultPartOid)
 
static ObjectAddress ATExecDetachPartitionFinalize (Relation rel, RangeVar *name)
 
static ObjectAddress ATExecAttachPartitionIdx (List **wqueue, Relation rel, RangeVar *name)
 
static void validatePartitionedIndex (Relation partedIdx, Relation partedTbl)
 
static void refuseDupeIndexAttach (Relation parentIdx, Relation partIdx, Relation partitionTbl)
 
static ListGetParentedForeignKeyRefs (Relation partition)
 
static void ATDetachCheckNoForeignKeyRefs (Relation partition)
 
static char GetAttributeCompression (Oid atttypid, char *compression)
 
ObjectAddress DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
 
static void DropErrorMsgNonExistent (RangeVar *rel, char rightkind, bool missing_ok)
 
static void DropErrorMsgWrongType (const char *relname, char wrongkind, char rightkind)
 
void RemoveRelations (DropStmt *drop)
 
void ExecuteTruncate (TruncateStmt *stmt)
 
void ExecuteTruncateGuts (List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs)
 
void SetRelationHasSubclass (Oid relationId, bool relhassubclass)
 
bool CheckRelationTableSpaceMove (Relation rel, Oid newTableSpaceId)
 
void SetRelationTableSpace (Relation rel, Oid newTableSpaceId, Oid newRelFileNode)
 
static void renameatt_check (Oid myrelid, Form_pg_class classform, bool recursing)
 
static AttrNumber renameatt_internal (Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
 
static void RangeVarCallbackForRenameAttribute (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
ObjectAddress renameatt (RenameStmt *stmt)
 
static ObjectAddress rename_constraint_internal (Oid myrelid, Oid mytypid, const char *oldconname, const char *newconname, bool recurse, bool recursing, int expected_parents)
 
ObjectAddress RenameConstraint (RenameStmt *stmt)
 
ObjectAddress RenameRelation (RenameStmt *stmt)
 
void RenameRelationInternal (Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
 
void 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 155 of file tablecmds.c.

◆ AT_PASS_ADD_COL

#define AT_PASS_ADD_COL   4 /* ADD COLUMN */

Definition at line 148 of file tablecmds.c.

◆ AT_PASS_ADD_CONSTR

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

Definition at line 149 of file tablecmds.c.

◆ AT_PASS_ADD_INDEX

#define AT_PASS_ADD_INDEX   8 /* ADD indexes */

Definition at line 152 of file tablecmds.c.

◆ AT_PASS_ADD_INDEXCONSTR

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

Definition at line 151 of file tablecmds.c.

◆ AT_PASS_ADD_OTHERCONSTR

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

Definition at line 153 of file tablecmds.c.

◆ AT_PASS_ALTER_TYPE

#define AT_PASS_ALTER_TYPE   1 /* ALTER COLUMN TYPE */

Definition at line 144 of file tablecmds.c.

◆ AT_PASS_COL_ATTRS

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

Definition at line 150 of file tablecmds.c.

◆ AT_PASS_DROP

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

Definition at line 143 of file tablecmds.c.

◆ AT_PASS_MISC

#define AT_PASS_MISC   10 /* other stuff */

Definition at line 154 of file tablecmds.c.

◆ AT_PASS_OLD_CONSTR

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

Definition at line 146 of file tablecmds.c.

◆ AT_PASS_OLD_INDEX

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

Definition at line 145 of file tablecmds.c.

◆ AT_PASS_UNSET

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

Definition at line 142 of file tablecmds.c.

◆ ATT_COMPOSITE_TYPE

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 318 of file tablecmds.c.

◆ ATT_FOREIGN_TABLE

#define ATT_FOREIGN_TABLE   0x0020

Definition at line 319 of file tablecmds.c.

◆ ATT_INDEX

#define ATT_INDEX   0x0008

Definition at line 317 of file tablecmds.c.

◆ ATT_MATVIEW

#define ATT_MATVIEW   0x0004

Definition at line 316 of file tablecmds.c.

◆ ATT_PARTITIONED_INDEX

#define ATT_PARTITIONED_INDEX   0x0040

Definition at line 320 of file tablecmds.c.

◆ ATT_SEQUENCE

#define ATT_SEQUENCE   0x0080

Definition at line 321 of file tablecmds.c.

◆ ATT_TABLE

#define ATT_TABLE   0x0001

Definition at line 314 of file tablecmds.c.

◆ ATT_VIEW

#define ATT_VIEW   0x0002

Definition at line 315 of file tablecmds.c.

◆ child_dependency_type

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

Definition at line 342 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 7134 of file tablecmds.c.

7135 {
7136  ObjectAddress myself,
7137  referenced;
7138 
7139  /* We know the default collation is pinned, so don't bother recording it */
7140  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7141  {
7142  myself.classId = RelationRelationId;
7143  myself.objectId = relid;
7144  myself.objectSubId = attnum;
7145  referenced.classId = CollationRelationId;
7146  referenced.objectId = collid;
7147  referenced.objectSubId = 0;
7148  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7149  }
7150 }
#define OidIsValid(objectId)
Definition: c.h:710
@ 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 7116 of file tablecmds.c.

7117 {
7118  ObjectAddress myself,
7119  referenced;
7120 
7121  myself.classId = RelationRelationId;
7122  myself.objectId = relid;
7123  myself.objectSubId = attnum;
7124  referenced.classId = TypeRelationId;
7125  referenced.objectId = typid;
7126  referenced.objectSubId = 0;
7127  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7128 }

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

9515 {
9516  ObjectAddress address;
9517  Oid constrOid;
9518  char *conname;
9519  bool conislocal;
9520  int coninhcount;
9521  bool connoinherit;
9522  Oid deleteTriggerOid,
9523  updateTriggerOid;
9524 
9525  /*
9526  * Verify relkind for each referenced partition. At the top level, this
9527  * is redundant with a previous check, but we need it when recursing.
9528  */
9529  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9530  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9531  ereport(ERROR,
9532  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9533  errmsg("referenced relation \"%s\" is not a table",
9534  RelationGetRelationName(pkrel))));
9535 
9536  /*
9537  * Caller supplies us with a constraint name; however, it may be used in
9538  * this partition, so come up with a different one in that case.
9539  */
9541  RelationGetRelid(rel),
9542  fkconstraint->conname))
9545  "fkey",
9546  RelationGetNamespace(rel), NIL);
9547  else
9548  conname = fkconstraint->conname;
9549 
9550  if (OidIsValid(parentConstr))
9551  {
9552  conislocal = false;
9553  coninhcount = 1;
9554  connoinherit = false;
9555  }
9556  else
9557  {
9558  conislocal = true;
9559  coninhcount = 0;
9560 
9561  /*
9562  * always inherit for partitioned tables, never for legacy inheritance
9563  */
9564  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
9565  }
9566 
9567  /*
9568  * Record the FK constraint in pg_constraint.
9569  */
9570  constrOid = CreateConstraintEntry(conname,
9571  RelationGetNamespace(rel),
9572  CONSTRAINT_FOREIGN,
9573  fkconstraint->deferrable,
9574  fkconstraint->initdeferred,
9575  fkconstraint->initially_valid,
9576  parentConstr,
9577  RelationGetRelid(rel),
9578  fkattnum,
9579  numfks,
9580  numfks,
9581  InvalidOid, /* not a domain constraint */
9582  indexOid,
9583  RelationGetRelid(pkrel),
9584  pkattnum,
9585  pfeqoperators,
9586  ppeqoperators,
9587  ffeqoperators,
9588  numfks,
9589  fkconstraint->fk_upd_action,
9590  fkconstraint->fk_del_action,
9591  fkdelsetcols,
9592  numfkdelsetcols,
9593  fkconstraint->fk_matchtype,
9594  NULL, /* no exclusion constraint */
9595  NULL, /* no check constraint */
9596  NULL,
9597  conislocal, /* islocal */
9598  coninhcount, /* inhcount */
9599  connoinherit, /* conNoInherit */
9600  false); /* is_internal */
9601 
9602  ObjectAddressSet(address, ConstraintRelationId, constrOid);
9603 
9604  /*
9605  * Mark the child constraint as part of the parent constraint; it must not
9606  * be dropped on its own. (This constraint is deleted when the partition
9607  * is detached, but a special check needs to occur that the partition
9608  * contains no referenced values.)
9609  */
9610  if (OidIsValid(parentConstr))
9611  {
9612  ObjectAddress referenced;
9613 
9614  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9615  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
9616  }
9617 
9618  /* make new constraint visible, in case we add more */
9620 
9621  /*
9622  * Create the action triggers that enforce the constraint.
9623  */
9625  fkconstraint,
9626  constrOid, indexOid,
9627  parentDelTrigger, parentUpdTrigger,
9628  &deleteTriggerOid, &updateTriggerOid);
9629 
9630  /*
9631  * If the referenced table is partitioned, recurse on ourselves to handle
9632  * each partition. We need one pg_constraint row created for each
9633  * partition in addition to the pg_constraint row for the parent table.
9634  */
9635  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9636  {
9637  PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
9638 
9639  for (int i = 0; i < pd->nparts; i++)
9640  {
9641  Relation partRel;
9642  AttrMap *map;
9643  AttrNumber *mapped_pkattnum;
9644  Oid partIndexId;
9645 
9646  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
9647 
9648  /*
9649  * Map the attribute numbers in the referenced side of the FK
9650  * definition to match the partition's column layout.
9651  */
9653  RelationGetDescr(pkrel));
9654  if (map)
9655  {
9656  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
9657  for (int j = 0; j < numfks; j++)
9658  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
9659  }
9660  else
9661  mapped_pkattnum = pkattnum;
9662 
9663  /* do the deed */
9664  partIndexId = index_get_partition(partRel, indexOid);
9665  if (!OidIsValid(partIndexId))
9666  elog(ERROR, "index for %u not found in partition %s",
9667  indexOid, RelationGetRelationName(partRel));
9668  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
9669  partIndexId, constrOid, numfks,
9670  mapped_pkattnum, fkattnum,
9671  pfeqoperators, ppeqoperators, ffeqoperators,
9672  numfkdelsetcols, fkdelsetcols,
9673  old_check_ok,
9674  deleteTriggerOid, updateTriggerOid);
9675 
9676  /* Done -- clean up (but keep the lock) */
9677  table_close(partRel, NoLock);
9678  if (map)
9679  {
9680  pfree(mapped_pkattnum);
9681  free_attrmap(map);
9682  }
9683  }
9684  }
9685 
9686  return address;
9687 }
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:259
void free_attrmap(AttrMap *map)
Definition: attmap.c:57
int16 AttrNumber
Definition: attnum.h:21
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define ereport(elevel,...)
Definition: elog.h:143
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:1175
void * palloc(Size size)
Definition: mcxt.c:1068
#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:65
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetRelid(relation)
Definition: rel.h:489
#define RelationGetDescr(relation)
Definition: rel.h:515
#define RelationGetRelationName(relation)
Definition: rel.h:523
#define RelationGetNamespace(relation)
Definition: rel.h:530
Definition: attmap.h:35
AttrNumber * attnums
Definition: attmap.h:36
bool initdeferred
Definition: parsenodes.h:2615
char fk_upd_action
Definition: parsenodes.h:2649
char fk_matchtype
Definition: parsenodes.h:2648
bool initially_valid
Definition: parsenodes.h:2658
bool deferrable
Definition: parsenodes.h:2614
char * conname
Definition: parsenodes.h:2613
char fk_del_action
Definition: parsenodes.h:2650
List * fk_attrs
Definition: parsenodes.h:2646
Form_pg_class rd_rel
Definition: rel.h:109
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8831
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentDelTrigger, Oid parentUpdTrigger, Oid *deleteTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:11653
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:9507
void CommandCounterIncrement(void)
Definition: xact.c:1074

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

9733 {
9734  Oid insertTriggerOid,
9735  updateTriggerOid;
9736 
9737  AssertArg(OidIsValid(parentConstr));
9738 
9739  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
9740  ereport(ERROR,
9741  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9742  errmsg("foreign key constraints are not supported on foreign tables")));
9743 
9744  /*
9745  * Add the check triggers to it and, if necessary, schedule it to be
9746  * checked in Phase 3.
9747  *
9748  * If the relation is partitioned, drill down to do it to its partitions.
9749  */
9751  RelationGetRelid(pkrel),
9752  fkconstraint,
9753  parentConstr,
9754  indexOid,
9755  parentInsTrigger, parentUpdTrigger,
9756  &insertTriggerOid, &updateTriggerOid);
9757 
9758  if (rel->rd_rel->relkind == RELKIND_RELATION)
9759  {
9760  /*
9761  * Tell Phase 3 to check that the constraint is satisfied by existing
9762  * rows. We can skip this during table creation, when requested
9763  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
9764  * and when we're recreating a constraint following a SET DATA TYPE
9765  * operation that did not impugn its validity.
9766  */
9767  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
9768  {
9769  NewConstraint *newcon;
9770  AlteredTableInfo *tab;
9771 
9772  tab = ATGetQueueEntry(wqueue, rel);
9773 
9774  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9775  newcon->name = get_constraint_name(parentConstr);
9776  newcon->contype = CONSTR_FOREIGN;
9777  newcon->refrelid = RelationGetRelid(pkrel);
9778  newcon->refindid = indexOid;
9779  newcon->conid = parentConstr;
9780  newcon->qual = (Node *) fkconstraint;
9781 
9782  tab->constraints = lappend(tab->constraints, newcon);
9783  }
9784  }
9785  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9786  {
9787  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
9788  Relation trigrel;
9789 
9790  /*
9791  * Triggers of the foreign keys will be manipulated a bunch of times
9792  * in the loop below. To avoid repeatedly opening/closing the trigger
9793  * catalog relation, we open it here and pass it to the subroutines
9794  * called below.
9795  */
9796  trigrel = table_open(TriggerRelationId, RowExclusiveLock);
9797 
9798  /*
9799  * Recurse to take appropriate action on each partition; either we
9800  * find an existing constraint to reparent to ours, or we create a new
9801  * one.
9802  */
9803  for (int i = 0; i < pd->nparts; i++)
9804  {
9805  Oid partitionId = pd->oids[i];
9806  Relation partition = table_open(partitionId, lockmode);
9807  List *partFKs;
9808  AttrMap *attmap;
9809  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
9810  bool attached;
9811  char *conname;
9812  Oid constrOid;
9813  ObjectAddress address,
9814  referenced;
9815  ListCell *cell;
9816 
9817  CheckTableNotInUse(partition, "ALTER TABLE");
9818 
9819  attmap = build_attrmap_by_name(RelationGetDescr(partition),
9820  RelationGetDescr(rel));
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)
Definition: attmap.c:174
#define AssertArg(condition)
Definition: c.h:806
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
List * lappend(List *list, void *datum)
Definition: list.c:336
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1106
void * palloc0(Size size)
Definition: mcxt.c:1099
#define copyObject(obj)
Definition: nodes.h:689
@ CONSTR_FOREIGN
Definition: parsenodes.h:2588
#define INDEX_MAX_KEYS
#define lfirst_node(type, lc)
Definition: pg_list.h:172
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4566
List * constraints
Definition: tablecmds.c:176
bool skip_validation
Definition: parsenodes.h:2657
Definition: pg_list.h:51
char * name
Definition: tablecmds.c:203
ConstrType contype
Definition: tablecmds.c:204
Node * qual
Definition: tablecmds.c:208
Definition: nodes.h:574
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:6038
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3989
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:10419
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:9726
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, Oid parentInsTrigger, Oid parentUpdTrigger, Oid *insertTrigOid, Oid *updateTrigOid)
Definition: tablecmds.c:11788

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

6072 {
6073  switch (cmdtype)
6074  {
6075  case AT_AddColumn:
6076  case AT_AddColumnRecurse:
6077  case AT_AddColumnToView:
6078  return "ADD COLUMN";
6079  case AT_ColumnDefault:
6081  return "ALTER COLUMN ... SET DEFAULT";
6082  case AT_DropNotNull:
6083  return "ALTER COLUMN ... DROP NOT NULL";
6084  case AT_SetNotNull:
6085  return "ALTER COLUMN ... SET NOT NULL";
6086  case AT_DropExpression:
6087  return "ALTER COLUMN ... DROP EXPRESSION";
6088  case AT_CheckNotNull:
6089  return NULL; /* not real grammar */
6090  case AT_SetStatistics:
6091  return "ALTER COLUMN ... SET STATISTICS";
6092  case AT_SetOptions:
6093  return "ALTER COLUMN ... SET";
6094  case AT_ResetOptions:
6095  return "ALTER COLUMN ... RESET";
6096  case AT_SetStorage:
6097  return "ALTER COLUMN ... SET STORAGE";
6098  case AT_SetCompression:
6099  return "ALTER COLUMN ... SET COMPRESSION";
6100  case AT_DropColumn:
6101  case AT_DropColumnRecurse:
6102  return "DROP COLUMN";
6103  case AT_AddIndex:
6104  case AT_ReAddIndex:
6105  return NULL; /* not real grammar */
6106  case AT_AddConstraint:
6108  case AT_ReAddConstraint:
6110  case AT_AddIndexConstraint:
6111  return "ADD CONSTRAINT";
6112  case AT_AlterConstraint:
6113  return "ALTER CONSTRAINT";
6114  case AT_ValidateConstraint:
6116  return "VALIDATE CONSTRAINT";
6117  case AT_DropConstraint:
6119  return "DROP CONSTRAINT";
6120  case AT_ReAddComment:
6121  return NULL; /* not real grammar */
6122  case AT_AlterColumnType:
6123  return "ALTER COLUMN ... SET DATA TYPE";
6125  return "ALTER COLUMN ... OPTIONS";
6126  case AT_ChangeOwner:
6127  return "OWNER TO";
6128  case AT_ClusterOn:
6129  return "CLUSTER ON";
6130  case AT_DropCluster:
6131  return "SET WITHOUT CLUSTER";
6132  case AT_SetAccessMethod:
6133  return "SET ACCESS METHOD";
6134  case AT_SetLogged:
6135  return "SET LOGGED";
6136  case AT_SetUnLogged:
6137  return "SET UNLOGGED";
6138  case AT_DropOids:
6139  return "SET WITHOUT OIDS";
6140  case AT_SetTableSpace:
6141  return "SET TABLESPACE";
6142  case AT_SetRelOptions:
6143  return "SET";
6144  case AT_ResetRelOptions:
6145  return "RESET";
6146  case AT_ReplaceRelOptions:
6147  return NULL; /* not real grammar */
6148  case AT_EnableTrig:
6149  return "ENABLE TRIGGER";
6150  case AT_EnableAlwaysTrig:
6151  return "ENABLE ALWAYS TRIGGER";
6152  case AT_EnableReplicaTrig:
6153  return "ENABLE REPLICA TRIGGER";
6154  case AT_DisableTrig:
6155  return "DISABLE TRIGGER";
6156  case AT_EnableTrigAll:
6157  return "ENABLE TRIGGER ALL";
6158  case AT_DisableTrigAll:
6159  return "DISABLE TRIGGER ALL";
6160  case AT_EnableTrigUser:
6161  return "ENABLE TRIGGER USER";
6162  case AT_DisableTrigUser:
6163  return "DISABLE TRIGGER USER";
6164  case AT_EnableRule:
6165  return "ENABLE RULE";
6166  case AT_EnableAlwaysRule:
6167  return "ENABLE ALWAYS RULE";
6168  case AT_EnableReplicaRule:
6169  return "ENABLE REPLICA RULE";
6170  case AT_DisableRule:
6171  return "DISABLE RULE";
6172  case AT_AddInherit:
6173  return "INHERIT";
6174  case AT_DropInherit:
6175  return "NO INHERIT";
6176  case AT_AddOf:
6177  return "OF";
6178  case AT_DropOf:
6179  return "NOT OF";
6180  case AT_ReplicaIdentity:
6181  return "REPLICA IDENTITY";
6182  case AT_EnableRowSecurity:
6183  return "ENABLE ROW SECURITY";
6184  case AT_DisableRowSecurity:
6185  return "DISABLE ROW SECURITY";
6186  case AT_ForceRowSecurity:
6187  return "FORCE ROW SECURITY";
6188  case AT_NoForceRowSecurity:
6189  return "NO FORCE ROW SECURITY";
6190  case AT_GenericOptions:
6191  return "OPTIONS";
6192  case AT_AttachPartition:
6193  return "ATTACH PARTITION";
6194  case AT_DetachPartition:
6195  return "DETACH PARTITION";
6197  return "DETACH PARTITION ... FINALIZE";
6198  case AT_AddIdentity:
6199  return "ALTER COLUMN ... ADD IDENTITY";
6200  case AT_SetIdentity:
6201  return "ALTER COLUMN ... SET";
6202  case AT_DropIdentity:
6203  return "ALTER COLUMN ... DROP IDENTITY";
6204  case AT_ReAddStatistics:
6205  return NULL; /* not real grammar */
6206  }
6207 
6208  return NULL;
6209 }
@ AT_AddIndexConstraint
Definition: parsenodes.h:2251
@ AT_DropOf
Definition: parsenodes.h:2283
@ AT_CheckNotNull
Definition: parsenodes.h:2234
@ AT_SetOptions
Definition: parsenodes.h:2236
@ AT_DropIdentity
Definition: parsenodes.h:2295
@ AT_DisableTrigUser
Definition: parsenodes.h:2275
@ AT_DropNotNull
Definition: parsenodes.h:2231
@ AT_AddOf
Definition: parsenodes.h:2282
@ AT_ResetOptions
Definition: parsenodes.h:2237
@ AT_ReplicaIdentity
Definition: parsenodes.h:2284
@ AT_DropColumnRecurse
Definition: parsenodes.h:2241
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2267
@ AT_EnableRowSecurity
Definition: parsenodes.h:2285
@ AT_AddColumnToView
Definition: parsenodes.h:2228
@ AT_ResetRelOptions
Definition: parsenodes.h:2266
@ AT_AddConstraintRecurse
Definition: parsenodes.h:2245
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2270
@ AT_DropOids
Definition: parsenodes.h:2262
@ AT_SetIdentity
Definition: parsenodes.h:2294
@ AT_ReAddStatistics
Definition: parsenodes.h:2296
@ AT_SetUnLogged
Definition: parsenodes.h:2261
@ AT_DisableTrig
Definition: parsenodes.h:2271
@ AT_SetCompression
Definition: parsenodes.h:2239
@ AT_DropExpression
Definition: parsenodes.h:2233
@ AT_AddIndex
Definition: parsenodes.h:2242
@ AT_EnableReplicaRule
Definition: parsenodes.h:2278
@ AT_ReAddIndex
Definition: parsenodes.h:2243
@ AT_DropConstraint
Definition: parsenodes.h:2252
@ AT_SetNotNull
Definition: parsenodes.h:2232
@ AT_ClusterOn
Definition: parsenodes.h:2258
@ AT_AddIdentity
Definition: parsenodes.h:2293
@ AT_ForceRowSecurity
Definition: parsenodes.h:2287
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2277
@ AT_SetAccessMethod
Definition: parsenodes.h:2263
@ AT_AlterColumnType
Definition: parsenodes.h:2255
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2292
@ AT_AddInherit
Definition: parsenodes.h:2280
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2247
@ AT_EnableTrig
Definition: parsenodes.h:2268
@ AT_AddColumnRecurse
Definition: parsenodes.h:2227
@ AT_DropColumn
Definition: parsenodes.h:2240
@ AT_ValidateConstraintRecurse
Definition: parsenodes.h:2250
@ AT_ReAddComment
Definition: parsenodes.h:2254
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2256
@ AT_DisableTrigAll
Definition: parsenodes.h:2273
@ AT_EnableRule
Definition: parsenodes.h:2276
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2288
@ AT_DetachPartition
Definition: parsenodes.h:2291
@ AT_SetStatistics
Definition: parsenodes.h:2235
@ AT_AttachPartition
Definition: parsenodes.h:2290
@ AT_AddConstraint
Definition: parsenodes.h:2244
@ AT_DropInherit
Definition: parsenodes.h:2281
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2269
@ AT_SetLogged
Definition: parsenodes.h:2260
@ AT_SetStorage
Definition: parsenodes.h:2238
@ AT_DisableRule
Definition: parsenodes.h:2279
@ AT_DisableRowSecurity
Definition: parsenodes.h:2286
@ AT_SetRelOptions
Definition: parsenodes.h:2265
@ AT_ChangeOwner
Definition: parsenodes.h:2257
@ AT_EnableTrigUser
Definition: parsenodes.h:2274
@ AT_ReAddConstraint
Definition: parsenodes.h:2246
@ AT_DropConstraintRecurse
Definition: parsenodes.h:2253
@ AT_SetTableSpace
Definition: parsenodes.h:2264
@ AT_GenericOptions
Definition: parsenodes.h:2289
@ AT_ColumnDefault
Definition: parsenodes.h:2229
@ AT_CookedColumnDefault
Definition: parsenodes.h:2230
@ AT_AlterConstraint
Definition: parsenodes.h:2248
@ AT_EnableTrigAll
Definition: parsenodes.h:2272
@ AT_DropCluster
Definition: parsenodes.h:2259
@ AT_ValidateConstraint
Definition: parsenodes.h:2249
@ AT_AddColumn
Definition: parsenodes.h:2226

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

16569 {
16570  List *indexList;
16571  ListCell *l;
16572 
16573  indexList = RelationGetIndexList(rel);
16574 
16575  foreach(l, indexList)
16576  {
16577  Oid indexOid = lfirst_oid(l);
16578  ObjectAddress thisobj;
16579 
16580  thisobj.classId = RelationRelationId;
16581  thisobj.objectId = indexOid;
16582  thisobj.objectSubId = 0;
16583 
16584  /*
16585  * Note: currently, the index will not have its own dependency on the
16586  * namespace, so we don't need to do changeDependencyFor(). There's no
16587  * row type in pg_type, either.
16588  *
16589  * XXX this objsMoved test may be pointless -- surely we have a single
16590  * dependency link from a relation to each index?
16591  */
16592  if (!object_address_present(&thisobj, objsMoved))
16593  {
16594  AlterRelationNamespaceInternal(classRel, indexOid,
16595  oldNspOid, newNspOid,
16596  false, objsMoved);
16597  add_exact_object_address(&thisobj, objsMoved);
16598  }
16599  }
16600 
16601  list_free(indexList);
16602 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2562
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2502
void list_free(List *list)
Definition: list.c:1505
#define lfirst_oid(lc)
Definition: pg_list.h:171
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4675
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16497

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

16501 {
16502  HeapTuple classTup;
16503  Form_pg_class classForm;
16504  ObjectAddress thisobj;
16505  bool already_done = false;
16506 
16507  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
16508  if (!HeapTupleIsValid(classTup))
16509  elog(ERROR, "cache lookup failed for relation %u", relOid);
16510  classForm = (Form_pg_class) GETSTRUCT(classTup);
16511 
16512  Assert(classForm->relnamespace == oldNspOid);
16513 
16514  thisobj.classId = RelationRelationId;
16515  thisobj.objectId = relOid;
16516  thisobj.objectSubId = 0;
16517 
16518  /*
16519  * If the object has already been moved, don't move it again. If it's
16520  * already in the right place, don't move it, but still fire the object
16521  * access hook.
16522  */
16523  already_done = object_address_present(&thisobj, objsMoved);
16524  if (!already_done && oldNspOid != newNspOid)
16525  {
16526  /* check for duplicate name (more friendly than unique-index failure) */
16527  if (get_relname_relid(NameStr(classForm->relname),
16528  newNspOid) != InvalidOid)
16529  ereport(ERROR,
16530  (errcode(ERRCODE_DUPLICATE_TABLE),
16531  errmsg("relation \"%s\" already exists in schema \"%s\"",
16532  NameStr(classForm->relname),
16533  get_namespace_name(newNspOid))));
16534 
16535  /* classTup is a copy, so OK to scribble on */
16536  classForm->relnamespace = newNspOid;
16537 
16538  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
16539 
16540  /* Update dependency on schema if caller said so */
16541  if (hasDependEntry &&
16542  changeDependencyFor(RelationRelationId,
16543  relOid,
16544  NamespaceRelationId,
16545  oldNspOid,
16546  newNspOid) != 1)
16547  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
16548  NameStr(classForm->relname));
16549  }
16550  if (!already_done)
16551  {
16552  add_exact_object_address(&thisobj, objsMoved);
16553 
16554  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
16555  }
16556 
16557  heap_freetuple(classTup);
16558 }
#define NameStr(name)
Definition: c.h:681
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
Assert(fmt[strlen(fmt) - 1] !='\n')
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3326
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1866
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:195
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:399
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
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 16612 of file tablecmds.c.

16615 {
16616  Relation depRel;
16617  SysScanDesc scan;
16618  ScanKeyData key[2];
16619  HeapTuple tup;
16620 
16621  /*
16622  * SERIAL sequences are those having an auto dependency on one of the
16623  * table's columns (we don't care *which* column, exactly).
16624  */
16625  depRel = table_open(DependRelationId, AccessShareLock);
16626 
16627  ScanKeyInit(&key[0],
16628  Anum_pg_depend_refclassid,
16629  BTEqualStrategyNumber, F_OIDEQ,
16630  ObjectIdGetDatum(RelationRelationId));
16631  ScanKeyInit(&key[1],
16632  Anum_pg_depend_refobjid,
16633  BTEqualStrategyNumber, F_OIDEQ,
16635  /* we leave refobjsubid unspecified */
16636 
16637  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
16638  NULL, 2, key);
16639 
16640  while (HeapTupleIsValid(tup = systable_getnext(scan)))
16641  {
16642  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
16643  Relation seqRel;
16644 
16645  /* skip dependencies other than auto dependencies on columns */
16646  if (depForm->refobjsubid == 0 ||
16647  depForm->classid != RelationRelationId ||
16648  depForm->objsubid != 0 ||
16649  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
16650  continue;
16651 
16652  /* Use relation_open just in case it's an index */
16653  seqRel = relation_open(depForm->objid, lockmode);
16654 
16655  /* skip non-sequence relations */
16656  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
16657  {
16658  /* No need to keep the lock */
16659  relation_close(seqRel, lockmode);
16660  continue;
16661  }
16662 
16663  /* Fix the pg_class and pg_depend entries */
16664  AlterRelationNamespaceInternal(classRel, depForm->objid,
16665  oldNspOid, newNspOid,
16666  true, objsMoved);
16667 
16668  /*
16669  * Sequences used to have entries in pg_type, but no longer do. If we
16670  * ever re-instate that, we'll need to move the pg_type entry to the
16671  * new namespace, too (using AlterTypeNamespaceInternal).
16672  */
16673  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
16674 
16675  /* Now we can close it. Keep the lock till end of transaction. */
16676  relation_close(seqRel, NoLock);
16677  }
16678 
16679  systable_endscan(scan);
16680 
16682 }
@ DEPENDENCY_AUTO
Definition: dependency.h:34
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:598
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:505
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:386
#define AccessShareLock
Definition: lockdefs.h:36
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
#define RelationGetForm(relation)
Definition: rel.h:483
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 4073 of file tablecmds.c.

4075 {
4076  Relation rel;
4077 
4078  /* Caller is required to provide an adequate lock. */
4079  rel = relation_open(context->relid, NoLock);
4080 
4081  CheckTableNotInUse(rel, "ALTER TABLE");
4082 
4083  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4084 }
RangeVar * relation
Definition: parsenodes.h:2218
bool inh
Definition: primnodes.h:69
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4418

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

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

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

4103 {
4104  Relation rel;
4105  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4106 
4107  rel = relation_open(relid, lockmode);
4108 
4110 
4111  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4112 }
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4147

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4017 of file tablecmds.c.

4018 {
4019  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4020  stmt->missing_ok ? RVR_MISSING_OK : 0,
4022  (void *) stmt);
4023 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:238
@ RVR_MISSING_OK
Definition: namespace.h:71
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:17011

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

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 14471 of file tablecmds.c.

14472 {
14473  List *relations = NIL;
14474  ListCell *l;
14475  ScanKeyData key[1];
14476  Relation rel;
14477  TableScanDesc scan;
14478  HeapTuple tuple;
14479  Oid orig_tablespaceoid;
14480  Oid new_tablespaceoid;
14481  List *role_oids = roleSpecsToIds(stmt->roles);
14482 
14483  /* Ensure we were not asked to move something we can't */
14484  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
14485  stmt->objtype != OBJECT_MATVIEW)
14486  ereport(ERROR,
14487  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14488  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
14489 
14490  /* Get the orig and new tablespace OIDs */
14491  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
14492  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
14493 
14494  /* Can't move shared relations in to or out of pg_global */
14495  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
14496  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
14497  new_tablespaceoid == GLOBALTABLESPACE_OID)
14498  ereport(ERROR,
14499  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14500  errmsg("cannot move relations in to or out of pg_global tablespace")));
14501 
14502  /*
14503  * Must have CREATE rights on the new tablespace, unless it is the
14504  * database default tablespace (which all users implicitly have CREATE
14505  * rights on).
14506  */
14507  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
14508  {
14509  AclResult aclresult;
14510 
14511  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
14512  ACL_CREATE);
14513  if (aclresult != ACLCHECK_OK)
14514  aclcheck_error(aclresult, OBJECT_TABLESPACE,
14515  get_tablespace_name(new_tablespaceoid));
14516  }
14517 
14518  /*
14519  * Now that the checks are done, check if we should set either to
14520  * InvalidOid because it is our database's default tablespace.
14521  */
14522  if (orig_tablespaceoid == MyDatabaseTableSpace)
14523  orig_tablespaceoid = InvalidOid;
14524 
14525  if (new_tablespaceoid == MyDatabaseTableSpace)
14526  new_tablespaceoid = InvalidOid;
14527 
14528  /* no-op */
14529  if (orig_tablespaceoid == new_tablespaceoid)
14530  return new_tablespaceoid;
14531 
14532  /*
14533  * Walk the list of objects in the tablespace and move them. This will
14534  * only find objects in our database, of course.
14535  */
14536  ScanKeyInit(&key[0],
14537  Anum_pg_class_reltablespace,
14538  BTEqualStrategyNumber, F_OIDEQ,
14539  ObjectIdGetDatum(orig_tablespaceoid));
14540 
14541  rel = table_open(RelationRelationId, AccessShareLock);
14542  scan = table_beginscan_catalog(rel, 1, key);
14543  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
14544  {
14545  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
14546  Oid relOid = relForm->oid;
14547 
14548  /*
14549  * Do not move objects in pg_catalog as part of this, if an admin
14550  * really wishes to do so, they can issue the individual ALTER
14551  * commands directly.
14552  *
14553  * Also, explicitly avoid any shared tables, temp tables, or TOAST
14554  * (TOAST will be moved with the main table).
14555  */
14556  if (IsCatalogNamespace(relForm->relnamespace) ||
14557  relForm->relisshared ||
14558  isAnyTempNamespace(relForm->relnamespace) ||
14559  IsToastNamespace(relForm->relnamespace))
14560  continue;
14561 
14562  /* Only move the object type requested */
14563  if ((stmt->objtype == OBJECT_TABLE &&
14564  relForm->relkind != RELKIND_RELATION &&
14565  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
14566  (stmt->objtype == OBJECT_INDEX &&
14567  relForm->relkind != RELKIND_INDEX &&
14568  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
14569  (stmt->objtype == OBJECT_MATVIEW &&
14570  relForm->relkind != RELKIND_MATVIEW))
14571  continue;
14572 
14573  /* Check if we are only moving objects owned by certain roles */
14574  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
14575  continue;
14576 
14577  /*
14578  * Handle permissions-checking here since we are locking the tables
14579  * and also to avoid doing a bunch of work only to fail part-way. Note
14580  * that permissions will also be checked by AlterTableInternal().
14581  *
14582  * Caller must be considered an owner on the table to move it.
14583  */
14584  if (!pg_class_ownercheck(relOid, GetUserId()))
14586  NameStr(relForm->relname));
14587 
14588  if (stmt->nowait &&
14590  ereport(ERROR,
14591  (errcode(ERRCODE_OBJECT_IN_USE),
14592  errmsg("aborting because lock on relation \"%s.%s\" is not available",
14593  get_namespace_name(relForm->relnamespace),
14594  NameStr(relForm->relname))));
14595  else
14597 
14598  /* Add to our list of objects to move */
14599  relations = lappend_oid(relations, relOid);
14600  }
14601 
14602  table_endscan(scan);
14604 
14605  if (relations == NIL)
14606  ereport(NOTICE,
14607  (errcode(ERRCODE_NO_DATA_FOUND),
14608  errmsg("no matching relations in tablespace \"%s\" found",
14609  orig_tablespaceoid == InvalidOid ? "(database default)" :
14610  get_tablespace_name(orig_tablespaceoid))));
14611 
14612  /* Everything is locked, loop through and move all of the relations. */
14613  foreach(l, relations)
14614  {
14615  List *cmds = NIL;
14617 
14618  cmd->subtype = AT_SetTableSpace;
14619  cmd->name = stmt->new_tablespacename;
14620 
14621  cmds = lappend(cmds, cmd);
14622 
14624  /* OID is set by AlterTableInternal */
14625  AlterTableInternal(lfirst_oid(l), cmds, false);
14627  }
14628 
14629  return new_tablespaceoid;
14630 }
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
@ ACLCHECK_NOT_OWNER
Definition: acl.h:184
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:5121
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:5171
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3512
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1520
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1474
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:202
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:184
#define NOTICE
Definition: elog.h:29
void EventTriggerAlterTableStart(Node *parsetree)
void EventTriggerAlterTableEnd(void)
Oid MyDatabaseTableSpace
Definition: globals.c:91
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1296
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:701
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:1984
Oid GetUserId(void)
Definition: miscinit.c:492
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3241
#define makeNode(_type_)
Definition: nodes.h:621
ObjectType get_relkind_objtype(char relkind)
@ OBJECT_MATVIEW
Definition: parsenodes.h:2157
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2176
@ OBJECT_INDEX
Definition: parsenodes.h:2154
@ OBJECT_TABLE
Definition: parsenodes.h:2175
#define ACL_CREATE
Definition: parsenodes.h:91
@ 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:4102
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1349

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

Referenced by ProcessUtilitySlow().

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 16360 of file tablecmds.c.

16361 {
16362  Relation rel;
16363  Oid relid;
16364  Oid oldNspOid;
16365  Oid nspOid;
16366  RangeVar *newrv;
16367  ObjectAddresses *objsMoved;
16368  ObjectAddress myself;
16369 
16371  stmt->missing_ok ? RVR_MISSING_OK : 0,
16373  (void *) stmt);
16374 
16375  if (!OidIsValid(relid))
16376  {
16377  ereport(NOTICE,
16378  (errmsg("relation \"%s\" does not exist, skipping",
16379  stmt->relation->relname)));
16380  return InvalidObjectAddress;
16381  }
16382 
16383  rel = relation_open(relid, NoLock);
16384 
16385  oldNspOid = RelationGetNamespace(rel);
16386 
16387  /* If it's an owned sequence, disallow moving it by itself. */
16388  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
16389  {
16390  Oid tableId;
16391  int32 colId;
16392 
16393  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
16394  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
16395  ereport(ERROR,
16396  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16397  errmsg("cannot move an owned sequence into another schema"),
16398  errdetail("Sequence \"%s\" is linked to table \"%s\".",
16400  get_rel_name(tableId))));
16401  }
16402 
16403  /* Get and lock schema OID and check its permissions. */
16404  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
16405  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
16406 
16407  /*
16408  * Check that setting the relation to a different schema won't result in a
16409  * publication having both a schema and the same schema's table, as this
16410  * is not supported.
16411  */
16412  if (stmt->objectType == OBJECT_TABLE)
16413  {
16414  ListCell *lc;
16415  List *schemaPubids = GetSchemaPublications(nspOid);
16416  List *relPubids = GetRelationPublications(RelationGetRelid(rel));
16417 
16418  foreach(lc, relPubids)
16419  {
16420  Oid pubid = lfirst_oid(lc);
16421 
16422  if (list_member_oid(schemaPubids, pubid))
16423  ereport(ERROR,
16424  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16425  errmsg("cannot move table \"%s\" to schema \"%s\"",
16426  RelationGetRelationName(rel), stmt->newschema),
16427  errdetail("The schema \"%s\" and same schema's table \"%s\" cannot be part of the same publication \"%s\".",
16428  stmt->newschema,
16430  get_publication_name(pubid, false)));
16431  }
16432  }
16433 
16434  /* common checks on switching namespaces */
16435  CheckSetNamespace(oldNspOid, nspOid);
16436 
16437  objsMoved = new_object_addresses();
16438  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
16439  free_object_addresses(objsMoved);
16440 
16441  ObjectAddressSet(myself, RelationRelationId, relid);
16442 
16443  if (oldschema)
16444  *oldschema = oldNspOid;
16445 
16446  /* close rel, but keep lock until commit */
16447  relation_close(rel, NoLock);
16448 
16449  return myself;
16450 }
signed int int32
Definition: c.h:429
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2447
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2742
int errdetail(const char *fmt,...)
Definition: elog.c:1037
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1909
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:423
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:536
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3013
const ObjectAddress InvalidObjectAddress
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:770
List * GetSchemaPublications(Oid schemaid)
List * GetRelationPublications(Oid relid)
char * get_publication_name(Oid pubid, bool missing_ok)
char * relname
Definition: primnodes.h:68
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16458

References AccessExclusiveLock, AlterTableNamespaceInternal(), CheckSetNamespace(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, ereport, errcode(), errdetail(), errmsg(), ERROR, free_object_addresses(), get_publication_name(), get_rel_name(), GetRelationPublications(), GetSchemaPublications(), InvalidObjectAddress, lfirst_oid, list_member_oid(), makeRangeVar(), AlterObjectSchemaStmt::missing_ok, new_object_addresses(), AlterObjectSchemaStmt::newschema, NoLock, NOTICE, OBJECT_TABLE, ObjectAddressSet, AlterObjectSchemaStmt::objectType, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelidExtended(), RelationData::rd_rel, AlterObjectSchemaStmt::relation, relation_close(), relation_open(), RelationGetNamespace, RelationGetRelationName, RelationGetRelid, RangeVar::relname, RVR_MISSING_OK, and sequenceIsOwned().

Referenced by ExecAlterObjectSchemaStmt().

◆ AlterTableNamespaceInternal()

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

Definition at line 16458 of file tablecmds.c.

16460 {
16461  Relation classRel;
16462 
16463  Assert(objsMoved != NULL);
16464 
16465  /* OK, modify the pg_class row and pg_depend entry */
16466  classRel = table_open(RelationRelationId, RowExclusiveLock);
16467 
16468  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
16469  nspOid, true, objsMoved);
16470 
16471  /* Fix the table's row type too, if it has one */
16472  if (OidIsValid(rel->rd_rel->reltype))
16473  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
16474  nspOid, false, false, objsMoved);
16475 
16476  /* Fix other dependent stuff */
16477  if (rel->rd_rel->relkind == RELKIND_RELATION ||
16478  rel->rd_rel->relkind == RELKIND_MATVIEW ||
16479  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16480  {
16481  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
16482  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
16483  objsMoved, AccessExclusiveLock);
16484  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
16485  false, objsMoved);
16486  }
16487 
16488  table_close(classRel, RowExclusiveLock);
16489 }
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:16612
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16567
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3957

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

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

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

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

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(), MemSet, NIL, NoLock, ObjectAddress::objectId, ObjectIdGetDatum, OidIsValid, Constraint::old_conpfeqop, Constraint::old_pktable_oid, AlteredTableInfo::oldDesc, Constraint::pk_attrs, Constraint::pktable, RelationData::rd_islocaltemp, RelationData::rd_rel, RelationGetDescr, RelationGetRelationName, RelationGetRelid, RelationIsPermanent, ReleaseSysCache(), SearchSysCache1(), ShareRowExclusiveLock, Constraint::skip_validation, strVal, table_close(), table_open(), table_openrv(), transformColumnNameList(), transformFkeyCheckAttrs(), transformFkeyGetPrimaryKey(), TupleDescAttr, and validateFkOnDeleteSetColumns().

Referenced by ATExecAddConstraint().

◆ ATCheckPartitionsNotInUse()

static void ATCheckPartitionsNotInUse ( Relation  rel,
LOCKMODE  lockmode 
)
static

Definition at line 6339 of file tablecmds.c.

6340 {
6341  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6342  {
6343  List *inh;
6344  ListCell *cell;
6345 
6346  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6347  /* first element is the parent rel; must ignore it */
6348  for_each_from(cell, inh, 1)
6349  {
6350  Relation childrel;
6351 
6352  /* find_all_inheritors already got lock */
6353  childrel = table_open(lfirst_oid(cell), NoLock);
6354  CheckTableNotInUse(childrel, "ALTER TABLE");
6355  table_close(childrel, NoLock);
6356  }
6357  list_free(inh);
6358  }
6359 }
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:393

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

12342 {
12343  Assert(expr != NULL);
12344 
12345  for (;;)
12346  {
12347  /* only one varno, so no need to check that */
12348  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
12349  return false;
12350  else if (IsA(expr, RelabelType))
12351  expr = (Node *) ((RelabelType *) expr)->arg;
12352  else if (IsA(expr, CoerceToDomain))
12353  {
12354  CoerceToDomain *d = (CoerceToDomain *) expr;
12355 
12357  return true;
12358  expr = (Node *) d->arg;
12359  }
12360  else if (IsA(expr, FuncExpr))
12361  {
12362  FuncExpr *f = (FuncExpr *) expr;
12363 
12364  switch (f->funcid)
12365  {
12366  case F_TIMESTAMPTZ_TIMESTAMP:
12367  case F_TIMESTAMP_TIMESTAMPTZ:
12369  return true;
12370  else
12371  expr = linitial(f->args);
12372  break;
12373  default:
12374  return true;
12375  }
12376  }
12377  else
12378  return true;
12379  }
12380 }
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:5518
void * arg
#define linitial(l)
Definition: pg_list.h:174
Oid funcid
Definition: primnodes.h:504
List * args
Definition: primnodes.h:512
Definition: primnodes.h:196
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 4418 of file tablecmds.c.

4421 {
4422  List *wqueue = NIL;
4423  ListCell *lcmd;
4424 
4425  /* Phase 1: preliminary examination of commands, create work queue */
4426  foreach(lcmd, cmds)
4427  {
4428  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4429 
4430  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4431  }
4432 
4433  /* Close the relation, but keep lock until commit */
4434  relation_close(rel, NoLock);
4435 
4436  /* Phase 2: update system catalogs */
4437  ATRewriteCatalogs(&wqueue, lockmode, context);
4438 
4439  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4440  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4441 }
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4826
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4453
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5379

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

19209 {
19210  List *constraints;
19211  ListCell *cell;
19212 
19213  constraints = GetParentedForeignKeyRefs(partition);
19214 
19215  foreach(cell, constraints)
19216  {
19217  Oid constrOid = lfirst_oid(cell);
19218  HeapTuple tuple;
19219  Form_pg_constraint constrForm;
19220  Relation rel;
19221  Trigger trig;
19222 
19223  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
19224  if (!HeapTupleIsValid(tuple))
19225  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
19226  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
19227 
19228  Assert(OidIsValid(constrForm->conparentid));
19229  Assert(constrForm->confrelid == RelationGetRelid(partition));
19230 
19231  /* prevent data changes into the referencing table until commit */
19232  rel = table_open(constrForm->conrelid, ShareLock);
19233 
19234  MemSet(&trig, 0, sizeof(trig));
19235  trig.tgoid = InvalidOid;
19236  trig.tgname = NameStr(constrForm->conname);
19238  trig.tgisinternal = true;
19239  trig.tgconstrrelid = RelationGetRelid(partition);
19240  trig.tgconstrindid = constrForm->conindid;
19241  trig.tgconstraint = constrForm->oid;
19242  trig.tgdeferrable = false;
19243  trig.tginitdeferred = false;
19244  /* we needn't fill in remaining fields */
19245 
19246  RI_PartitionRemove_Check(&trig, rel, partition);
19247 
19248  ReleaseSysCache(tuple);
19249 
19250  table_close(rel, NoLock);
19251  }
19252 }
#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:1649
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:19155
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:149

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

Referenced by ATExecDetachPartition().

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 16888 of file tablecmds.c.

16890 {
16891  ListCell *cur_item;
16892 
16893  foreach(cur_item, on_commits)
16894  {
16895  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16896 
16897  if (!isCommit && oc->creating_subid == mySubid)
16898  {
16899  /* cur_item must be removed */
16901  pfree(oc);
16902  }
16903  else
16904  {
16905  /* cur_item must be preserved */
16906  if (oc->creating_subid == mySubid)
16907  oc->creating_subid = parentSubid;
16908  if (oc->deleting_subid == mySubid)
16909  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
16910  }
16911  }
16912 }
#define InvalidSubTransactionId
Definition: c.h:593
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
SubTransactionId creating_subid
Definition: tablecmds.c:121
SubTransactionId deleting_subid
Definition: tablecmds.c:122
static List * on_commits
Definition: tablecmds.c:125

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

16857 {
16858  ListCell *cur_item;
16859 
16860  foreach(cur_item, on_commits)
16861  {
16862  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16863 
16864  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
16866  {
16867  /* cur_item must be removed */
16869  pfree(oc);
16870  }
16871  else
16872  {
16873  /* cur_item must be preserved */
16876  }
16877  }
16878 }

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

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

Referenced by ATExecCmd().

◆ ATExecAddConstraint()

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

Definition at line 8758 of file tablecmds.c.

8761 {
8763 
8764  Assert(IsA(newConstraint, Constraint));
8765 
8766  /*
8767  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
8768  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
8769  * switch anyway to make it easier to add more code later.
8770  */
8771  switch (newConstraint->contype)
8772  {
8773  case CONSTR_CHECK:
8774  address =
8775  ATAddCheckConstraint(wqueue, tab, rel,
8776  newConstraint, recurse, false, is_readd,
8777  lockmode);
8778  break;
8779 
8780  case CONSTR_FOREIGN:
8781 
8782  /*
8783  * Assign or validate constraint name
8784  */
8785  if (newConstraint->conname)
8786  {
8788  RelationGetRelid(rel),
8789  newConstraint->conname))
8790  ereport(ERROR,
8792  errmsg("constraint \"%s\" for relation \"%s\" already exists",
8793  newConstraint->conname,
8794  RelationGetRelationName(rel))));
8795  }
8796  else
8797  newConstraint->conname =
8800  "fkey",
8801  RelationGetNamespace(rel),
8802  NIL);
8803 
8804  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
8805  newConstraint,
8806  recurse, false,
8807  lockmode);
8808  break;
8809 
8810  default:
8811  elog(ERROR, "unrecognized constraint type: %d",
8812  (int) newConstraint->contype);
8813  }
8814 
8815  return address;
8816 }
@ CONSTR_CHECK
Definition: parsenodes.h:2584
#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:9010

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

7648 {
7649  Relation attrelation;
7650  HeapTuple tuple;
7651  Form_pg_attribute attTup;
7653  ObjectAddress address;
7654  ColumnDef *cdef = castNode(ColumnDef, def);
7655 
7656  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7657 
7658  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7659  if (!HeapTupleIsValid(tuple))
7660  ereport(ERROR,
7661  (errcode(ERRCODE_UNDEFINED_COLUMN),
7662  errmsg("column \"%s\" of relation \"%s\" does not exist",
7663  colName, RelationGetRelationName(rel))));
7664  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7665  attnum = attTup->attnum;
7666 
7667  /* Can't alter a system attribute */
7668  if (attnum <= 0)
7669  ereport(ERROR,
7670  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7671  errmsg("cannot alter system column \"%s\"",
7672  colName)));
7673 
7674  /*
7675  * Creating a column as identity implies NOT NULL, so adding the identity
7676  * to an existing column that is not NOT NULL would create a state that
7677  * cannot be reproduced without contortions.
7678  */
7679  if (!attTup->attnotnull)
7680  ereport(ERROR,
7681  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7682  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
7683  colName, RelationGetRelationName(rel))));
7684 
7685  if (attTup->attidentity)
7686  ereport(ERROR,
7687  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7688  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
7689  colName, RelationGetRelationName(rel))));
7690 
7691  if (attTup->atthasdef)
7692  ereport(ERROR,
7693  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7694  errmsg("column \"%s\" of relation \"%s\" already has a default value",
7695  colName, RelationGetRelationName(rel))));
7696 
7697  attTup->attidentity = cdef->identity;
7698  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7699 
7700  InvokeObjectPostAlterHook(RelationRelationId,
7701  RelationGetRelid(rel),
7702  attTup->attnum);
7703  ObjectAddressSubSet(address, RelationRelationId,
7704  RelationGetRelid(rel), attnum);
7705  heap_freetuple(tuple);
7706 
7707  table_close(attrelation, RowExclusiveLock);
7708 
7709  return address;
7710 }

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

8585 {
8586  bool check_rights;
8587  bool skip_build;
8588  bool quiet;
8589  ObjectAddress address;
8590 
8591  Assert(IsA(stmt, IndexStmt));
8592  Assert(!stmt->concurrent);
8593 
8594  /* The IndexStmt has already been through transformIndexStmt */
8595  Assert(stmt->transformed);
8596 
8597  /* suppress schema rights check when rebuilding existing index */
8598  check_rights = !is_rebuild;
8599  /* skip index build if phase 3 will do it or we're reusing an old one */
8600  skip_build = tab->rewrite > 0 || OidIsValid(stmt->oldNode);
8601  /* suppress notices when rebuilding existing index */
8602  quiet = is_rebuild;
8603 
8604  address = DefineIndex(RelationGetRelid(rel),
8605  stmt,
8606  InvalidOid, /* no predefined OID */
8607  InvalidOid, /* no parent index */
8608  InvalidOid, /* no parent constraint */
8609  true, /* is_alter_table */
8610  check_rights,
8611  false, /* check_not_in_use - we did it already */
8612  skip_build,
8613  quiet);
8614 
8615  /*
8616  * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
8617  * index instead of building from scratch. Restore associated fields.
8618  * This may store InvalidSubTransactionId in both fields, in which case
8619  * relcache.c will assume it can rebuild the relcache entry. Hence, do
8620  * this after the CCI that made catalog rows visible to any rebuild. The
8621  * DROP of the old edition of this index will have scheduled the storage
8622  * for deletion at commit, so cancel that pending deletion.
8623  */
8624  if (OidIsValid(stmt->oldNode))
8625  {
8626  Relation irel = index_open(address.objectId, NoLock);
8627 
8628  irel->rd_createSubid = stmt->oldCreateSubid;
8630  RelationPreserveStorage(irel->rd_node, true);
8631  index_close(irel, NoLock);
8632  }
8633 
8634  return address;
8635 }
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:506
void RelationPreserveStorage(RelFileNode rnode, bool atCommit)
Definition: storage.c:250
bool transformed
Definition: parsenodes.h:3259
SubTransactionId oldFirstRelfilenodeSubid
Definition: parsenodes.h:3251
SubTransactionId oldCreateSubid
Definition: parsenodes.h:3250
bool concurrent
Definition: parsenodes.h:3260
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
RelFileNode rd_node
Definition: rel.h:56
SubTransactionId rd_createSubid
Definition: rel.h:102

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

Referenced by ATExecCmd().

◆ ATExecAddIndexConstraint()

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

Definition at line 8666 of file tablecmds.c.

8668 {
8669  Oid index_oid = stmt->indexOid;
8670  Relation indexRel;
8671  char *indexName;
8672  IndexInfo *indexInfo;
8673  char *constraintName;
8674  char constraintType;
8675  ObjectAddress address;
8676  bits16 flags;
8677 
8678  Assert(IsA(stmt, IndexStmt));
8679  Assert(OidIsValid(index_oid));
8680  Assert(stmt->isconstraint);
8681 
8682  /*
8683  * Doing this on partitioned tables is not a simple feature to implement,
8684  * so let's punt for now.
8685  */
8686  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8687  ereport(ERROR,
8688  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8689  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
8690 
8691  indexRel = index_open(index_oid, AccessShareLock);
8692 
8693  indexName = pstrdup(RelationGetRelationName(indexRel));
8694 
8695  indexInfo = BuildIndexInfo(indexRel);
8696 
8697  /* this should have been checked at parse time */
8698  if (!indexInfo->ii_Unique)
8699  elog(ERROR, "index \"%s\" is not unique", indexName);
8700 
8701  /*
8702  * Determine name to assign to constraint. We require a constraint to
8703  * have the same name as the underlying index; therefore, use the index's
8704  * existing name as the default constraint name, and if the user
8705  * explicitly gives some other name for the constraint, rename the index
8706  * to match.
8707  */
8708  constraintName = stmt->idxname;
8709  if (constraintName == NULL)
8710  constraintName = indexName;
8711  else if (strcmp(constraintName, indexName) != 0)
8712  {
8713  ereport(NOTICE,
8714  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
8715  indexName, constraintName)));
8716  RenameRelationInternal(index_oid, constraintName, false, true);
8717  }
8718 
8719  /* Extra checks needed if making primary key */
8720  if (stmt->primary)
8721  index_check_primary_key(rel, indexInfo, true, stmt);
8722 
8723  /* Note we currently don't support EXCLUSION constraints here */
8724  if (stmt->primary)
8725  constraintType = CONSTRAINT_PRIMARY;
8726  else
8727  constraintType = CONSTRAINT_UNIQUE;
8728 
8729  /* Create the catalog entries for the constraint */
8735 
8736  address = index_constraint_create(rel,
8737  index_oid,
8738  InvalidOid,
8739  indexInfo,
8740  constraintName,
8741  constraintType,
8742  flags,
8744  false); /* is_internal */
8745 
8746  index_close(indexRel, NoLock);
8747 
8748  return address;
8749 }
uint16 bits16
Definition: c.h:449
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:1898
void index_check_primary_key(Relation heapRel, IndexInfo *indexInfo, bool is_alter_table, IndexStmt *stmt)
Definition: index.c:205
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2418
#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:1305
bool ii_Unique
Definition: execnodes.h:175
bool deferrable
Definition: parsenodes.h:3257
Oid indexOid
Definition: parsenodes.h:3248
bool initdeferred
Definition: parsenodes.h:3258
bool isconstraint
Definition: parsenodes.h:3256
char * idxname
Definition: parsenodes.h:3237
bool primary
Definition: parsenodes.h:3255
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3846

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

14741 {
14742  Relation parent_rel;
14743  List *children;
14744  ObjectAddress address;
14745  const char *trigger_name;
14746 
14747  /*
14748  * A self-exclusive lock is needed here. See the similar case in
14749  * MergeAttributes() for a full explanation.
14750  */
14751  parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
14752 
14753  /*
14754  * Must be owner of both parent and child -- child was checked by
14755  * ATSimplePermissions call in ATPrepCmd
14756  */
14758 
14759  /* Permanent rels cannot inherit from temporary ones */
14760  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
14761  child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
14762  ereport(ERROR,
14763  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14764  errmsg("cannot inherit from temporary relation \"%s\"",
14765  RelationGetRelationName(parent_rel))));
14766 
14767  /* If parent rel is temp, it must belong to this session */
14768  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
14769  !parent_rel->rd_islocaltemp)
14770  ereport(ERROR,
14771  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14772  errmsg("cannot inherit from temporary relation of another session")));
14773 
14774  /* Ditto for the child */
14775  if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
14776  !child_rel->rd_islocaltemp)
14777  ereport(ERROR,
14778  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14779  errmsg("cannot inherit to temporary relation of another session")));
14780 
14781  /* Prevent partitioned tables from becoming inheritance parents */
14782  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14783  ereport(ERROR,
14784  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14785  errmsg("cannot inherit from partitioned table \"%s\"",
14786  parent->relname)));
14787 
14788  /* Likewise for partitions */
14789  if (parent_rel->rd_rel->relispartition)
14790  ereport(ERROR,
14791  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
14792  errmsg("cannot inherit from a partition")));
14793 
14794  /*
14795  * Prevent circularity by seeing if proposed parent inherits from child.
14796  * (In particular, this disallows making a rel inherit from itself.)
14797  *
14798  * This is not completely bulletproof because of race conditions: in
14799  * multi-level inheritance trees, someone else could concurrently be
14800  * making another inheritance link that closes the loop but does not join
14801  * either of the rels we have locked. Preventing that seems to require
14802  * exclusive locks on the entire inheritance tree, which is a cure worse
14803  * than the disease. find_all_inheritors() will cope with circularity
14804  * anyway, so don't sweat it too much.
14805  *
14806  * We use weakest lock we can on child's children, namely AccessShareLock.
14807  */
14808  children = find_all_inheritors(RelationGetRelid(child_rel),
14809  AccessShareLock, NULL);
14810 
14811  if (list_member_oid(children, RelationGetRelid(parent_rel)))
14812  ereport(ERROR,
14813  (errcode(ERRCODE_DUPLICATE_TABLE),
14814  errmsg("circular inheritance not allowed"),
14815  errdetail("\"%s\" is already a child of \"%s\".",
14816  parent->relname,
14817  RelationGetRelationName(child_rel))));
14818 
14819  /*
14820  * If child_rel has row-level triggers with transition tables, we
14821  * currently don't allow it to become an inheritance child. See also
14822  * prohibitions in ATExecAttachPartition() and CreateTrigger().
14823  */
14824  trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
14825  if (trigger_name != NULL)
14826  ereport(ERROR,
14827  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14828  errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
14829  trigger_name, RelationGetRelationName(child_rel)),
14830  errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
14831 
14832  /* OK to create inheritance */
14833  CreateInheritance(child_rel, parent_rel);
14834 
14835  ObjectAddressSet(address, RelationRelationId,
14836  RelationGetRelid(parent_rel));
14837 
14838  /* keep our lock on the parent relation until commit */
14839  table_close(parent_rel, NoLock);
14840 
14841  return address;
14842 }
TriggerDesc * trigdesc
Definition: rel.h:115
static void CreateInheritance(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:14852
const char * FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc)
Definition: trigger.c:2286

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

15625 {
15626  Oid relid = RelationGetRelid(rel);
15627  Type typetuple;
15628  Form_pg_type typeform;
15629  Oid typeid;
15630  Relation inheritsRelation,
15631  relationRelation;
15632  SysScanDesc scan;
15633  ScanKeyData key;
15634  AttrNumber table_attno,
15635  type_attno;
15636  TupleDesc typeTupleDesc,
15637  tableTupleDesc;
15638  ObjectAddress tableobj,
15639  typeobj;
15640  HeapTuple classtuple;
15641 
15642  /* Validate the type. */
15643  typetuple = typenameType(NULL, ofTypename, NULL);
15644  check_of_type(typetuple);
15645  typeform = (Form_pg_type) GETSTRUCT(typetuple);
15646  typeid = typeform->oid;
15647 
15648  /* Fail if the table has any inheritance parents. */
15649  inheritsRelation = table_open(InheritsRelationId, AccessShareLock);
15650  ScanKeyInit(&key,
15651  Anum_pg_inherits_inhrelid,
15652  BTEqualStrategyNumber, F_OIDEQ,
15653  ObjectIdGetDatum(relid));
15654  scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
15655  true, NULL, 1, &key);
15657  ereport(ERROR,
15658  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
15659  errmsg("typed tables cannot inherit")));
15660  systable_endscan(scan);
15661  table_close(inheritsRelation, AccessShareLock);
15662 
15663  /*
15664  * Check the tuple descriptors for compatibility. Unlike inheritance, we
15665  * require that the order also match. However, attnotnull need not match.
15666  */
15667  typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
15668  tableTupleDesc = RelationGetDescr(rel);
15669  table_attno = 1;
15670  for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
15671  {
15672  Form_pg_attribute type_attr,
15673  table_attr;
15674  const char *type_attname,
15675  *table_attname;
15676 
15677  /* Get the next non-dropped type attribute. */
15678  type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
15679  if (type_attr->attisdropped)
15680  continue;
15681  type_attname = NameStr(type_attr->attname);
15682 
15683  /* Get the next non-dropped table attribute. */
15684  do
15685  {
15686  if (table_attno > tableTupleDesc->natts)
15687  ereport(ERROR,
15688  (errcode(ERRCODE_DATATYPE_MISMATCH),
15689  errmsg("table is missing column \"%s\"",
15690  type_attname)));
15691  table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
15692  table_attno++;
15693  } while (table_attr->attisdropped);
15694  table_attname = NameStr(table_attr->attname);
15695 
15696  /* Compare name. */
15697  if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
15698  ereport(ERROR,
15699  (errcode(ERRCODE_DATATYPE_MISMATCH),
15700  errmsg("table has column \"%s\" where type requires \"%s\"",
15701  table_attname, type_attname)));
15702 
15703  /* Compare type. */
15704  if (table_attr->atttypid != type_attr->atttypid ||
15705  table_attr->atttypmod != type_attr->atttypmod ||
15706  table_attr->attcollation != type_attr->attcollation)
15707  ereport(ERROR,
15708  (errcode(ERRCODE_DATATYPE_MISMATCH),
15709  errmsg("table \"%s\" has different type for column \"%s\"",
15710  RelationGetRelationName(rel), type_attname)));
15711  }
15712  ReleaseTupleDesc(typeTupleDesc);
15713 
15714  /* Any remaining columns at the end of the table had better be dropped. */
15715  for (; table_attno <= tableTupleDesc->natts; table_attno++)
15716  {
15717  Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
15718  table_attno - 1);
15719 
15720  if (!table_attr->attisdropped)
15721  ereport(ERROR,
15722  (errcode(ERRCODE_DATATYPE_MISMATCH),
15723  errmsg("table has extra column \"%s\"",
15724  NameStr(table_attr->attname))));
15725  }
15726 
15727  /* If the table was already typed, drop the existing dependency. */
15728  if (rel->rd_rel->reloftype)
15729  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
15731 
15732  /* Record a dependency on the new type. */
15733  tableobj.classId = RelationRelationId;
15734  tableobj.objectId = relid;
15735  tableobj.objectSubId = 0;
15736  typeobj.classId = TypeRelationId;
15737  typeobj.objectId = typeid;
15738  typeobj.objectSubId = 0;
15739  recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
15740 
15741  /* Update pg_class.reloftype */
15742  relationRelation = table_open(RelationRelationId, RowExclusiveLock);
15743  classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
15744  if (!HeapTupleIsValid(classtuple))
15745  elog(ERROR, "cache lookup failed for relation %u", relid);
15746  ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
15747  CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
15748 
15749  InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
15750 
15751  heap_freetuple(classtuple);
15752  table_close(relationRelation, RowExclusiveLock);
15753 
15754  ReleaseSysCache(typetuple);
15755 
15756  return typeobj;
15757 }
#define NAMEDATALEN
static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
Definition: tablecmds.c:15572
void check_of_type(HeapTuple typetuple)
Definition: tablecmds.c:6581
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1830

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 * <