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

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Functions

static void truncate_check_rel (Oid relid, Form_pg_class reltuple)
 
static void truncate_check_perms (Oid relid, Form_pg_class reltuple)
 
static void truncate_check_activity (Relation rel)
 
static void 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, bool old_check_ok)
 
static void addFkRecurseReferencing (List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok, LOCKMODE lockmode)
 
static void CloneForeignKeyConstraints (List **wqueue, Relation parentRel, Relation partitionRel)
 
static void CloneFkReferenced (Relation parentRel, Relation partitionRel)
 
static void CloneFkReferencing (List **wqueue, Relation parentRel, Relation partRel)
 
static void createForeignKeyCheckTriggers (Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
 
static void createForeignKeyActionTriggers (Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
 
static bool tryAttachPartitionForeignKey (ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop)
 
static void ATExecDropConstraint (Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode)
 
static void ATPrepAlterColumnType (List **wqueue, AlteredTableInfo *tab, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static bool ATColumnChangeRequiresRewrite (Node *expr, AttrNumber varattno)
 
static ObjectAddress ATExecAlterColumnType (AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static void RememberConstraintForRebuilding (Oid conoid, AlteredTableInfo *tab)
 
static void RememberIndexForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
static void RememberStatisticsForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
static void ATPostAlterTypeCleanup (List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
 
static void ATPostAlterTypeParse (Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, List **wqueue, LOCKMODE lockmode, bool rewrite)
 
static void RebuildConstraintComment (AlteredTableInfo *tab, int pass, Oid objid, Relation rel, List *domname, const char *conname)
 
static void TryReuseIndex (Oid oldId, IndexStmt *stmt)
 
static void TryReuseForeignKey (Oid oldId, Constraint *con)
 
static ObjectAddress ATExecAlterColumnGenericOptions (Relation rel, const char *colName, List *options, LOCKMODE lockmode)
 
static void change_owner_fix_column_acls (Oid relationOid, Oid oldOwnerId, Oid newOwnerId)
 
static void change_owner_recurse_to_sequences (Oid relationOid, Oid newOwnerId, LOCKMODE lockmode)
 
static ObjectAddress ATExecClusterOn (Relation rel, const char *indexName, LOCKMODE lockmode)
 
static void ATExecDropCluster (Relation rel, LOCKMODE lockmode)
 
static 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 void CreateFKCheckTrigger (Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, bool on_insert)
 
static void RememberReplicaIdentityForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
static void RememberClusterOnForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
void ATExecChangeOwner (Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
 
Oid AlterTableMoveAll (AlterTableMoveAllStmt *stmt)
 
static char * decompile_conbin (HeapTuple contup, TupleDesc tupdesc)
 
static bool constraints_equivalent (HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
 
static void MarkInheritDetached (Relation child_rel, Relation parent_rel)
 
static void relation_mark_replica_identity (Relation rel, char ri_type, Oid indexOid, bool is_internal)
 
ObjectAddress AlterTableNamespace (AlterObjectSchemaStmt *stmt, Oid *oldschema)
 
void AlterTableNamespaceInternal (Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
 
void AlterRelationNamespaceInternal (Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
 
void register_on_commit_action (Oid relid, OnCommitAction action)
 
void remove_on_commit_action (Oid relid)
 
void PreCommit_on_commit_actions (void)
 
void AtEOXact_on_commit_actions (bool isCommit)
 
void AtEOSubXact_on_commit_actions (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
void RangeVarCallbackOwnsTable (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
void RangeVarCallbackOwnsRelation (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
bool PartConstraintImpliedByRelConstraint (Relation scanrel, List *partConstraint)
 
static void RangeVarCallbackForAttachIndex (const RangeVar *rv, Oid relOid, Oid oldRelOid, void *arg)
 

Variables

static Liston_commits = NIL
 
static const struct dropmsgstrings dropmsgstringarray []
 

Macro Definition Documentation

◆ AT_NUM_PASSES

#define AT_NUM_PASSES   11

Definition at line 153 of file tablecmds.c.

Referenced by ATRewriteCatalogs().

◆ AT_PASS_ADD_COL

#define AT_PASS_ADD_COL   4 /* ADD COLUMN */

Definition at line 146 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_ADD_CONSTR

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

Definition at line 147 of file tablecmds.c.

Referenced by ATExecCmd(), and ATPrepCmd().

◆ AT_PASS_ADD_INDEX

#define AT_PASS_ADD_INDEX   8 /* ADD indexes */

Definition at line 150 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_ADD_INDEXCONSTR

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

Definition at line 149 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_ADD_OTHERCONSTR

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

Definition at line 151 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_ALTER_TYPE

#define AT_PASS_ALTER_TYPE   1 /* ALTER COLUMN TYPE */

Definition at line 142 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATRewriteCatalogs().

◆ AT_PASS_COL_ATTRS

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

Definition at line 148 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_DROP

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

Definition at line 141 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_MISC

#define AT_PASS_MISC   10 /* other stuff */

Definition at line 152 of file tablecmds.c.

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

◆ AT_PASS_OLD_CONSTR

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

Definition at line 144 of file tablecmds.c.

Referenced by ATPostAlterTypeCleanup(), and ATPostAlterTypeParse().

◆ AT_PASS_OLD_INDEX

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

Definition at line 143 of file tablecmds.c.

Referenced by ATPostAlterTypeParse().

◆ AT_PASS_UNSET

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

Definition at line 140 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ ATT_COMPOSITE_TYPE

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 310 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATSimplePermissions().

◆ ATT_FOREIGN_TABLE

◆ ATT_INDEX

#define ATT_INDEX   0x0008

Definition at line 309 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATSimplePermissions().

◆ ATT_MATVIEW

#define ATT_MATVIEW   0x0004

Definition at line 308 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATSimplePermissions().

◆ ATT_PARTITIONED_INDEX

#define ATT_PARTITIONED_INDEX   0x0040

Definition at line 312 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATSimplePermissions().

◆ ATT_TABLE

◆ ATT_VIEW

#define ATT_VIEW   0x0002

Definition at line 307 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATSimplePermissions().

◆ child_dependency_type

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

Definition at line 333 of file tablecmds.c.

Referenced by RemoveInheritance(), and StoreCatalogInheritance1().

Typedef Documentation

◆ AlteredTableInfo

◆ ForeignTruncateInfo

◆ NewColumnValue

◆ NewConstraint

typedef struct NewConstraint NewConstraint

◆ OnCommitItem

typedef struct OnCommitItem OnCommitItem

Function Documentation

◆ add_column_collation_dependency()

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

Definition at line 7062 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

7063 {
7064  ObjectAddress myself,
7065  referenced;
7066 
7067  /* We know the default collation is pinned, so don't bother recording it */
7068  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7069  {
7070  myself.classId = RelationRelationId;
7071  myself.objectId = relid;
7072  myself.objectSubId = attnum;
7073  referenced.classId = CollationRelationId;
7074  referenced.objectId = collid;
7075  referenced.objectSubId = 0;
7076  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7077  }
7078 }
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
#define OidIsValid(objectId)
Definition: c.h:710
int16 attnum
Definition: pg_attribute.h:83

◆ add_column_datatype_dependency()

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

Definition at line 7044 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

7045 {
7046  ObjectAddress myself,
7047  referenced;
7048 
7049  myself.classId = RelationRelationId;
7050  myself.objectId = relid;
7051  myself.objectSubId = attnum;
7052  referenced.classId = TypeRelationId;
7053  referenced.objectId = typid;
7054  referenced.objectSubId = 0;
7055  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7056 }
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
int16 attnum
Definition: pg_attribute.h:83

◆ addFkRecurseReferenced()

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

Definition at line 9390 of file tablecmds.c.

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

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferenced().

9395 {
9396  ObjectAddress address;
9397  Oid constrOid;
9398  char *conname;
9399  bool conislocal;
9400  int coninhcount;
9401  bool connoinherit;
9402 
9403  /*
9404  * Verify relkind for each referenced partition. At the top level, this
9405  * is redundant with a previous check, but we need it when recursing.
9406  */
9407  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9408  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9409  ereport(ERROR,
9410  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9411  errmsg("referenced relation \"%s\" is not a table",
9412  RelationGetRelationName(pkrel))));
9413 
9414  /*
9415  * Caller supplies us with a constraint name; however, it may be used in
9416  * this partition, so come up with a different one in that case.
9417  */
9419  RelationGetRelid(rel),
9420  fkconstraint->conname))
9423  "fkey",
9424  RelationGetNamespace(rel), NIL);
9425  else
9426  conname = fkconstraint->conname;
9427 
9428  if (OidIsValid(parentConstr))
9429  {
9430  conislocal = false;
9431  coninhcount = 1;
9432  connoinherit = false;
9433  }
9434  else
9435  {
9436  conislocal = true;
9437  coninhcount = 0;
9438 
9439  /*
9440  * always inherit for partitioned tables, never for legacy inheritance
9441  */
9442  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
9443  }
9444 
9445  /*
9446  * Record the FK constraint in pg_constraint.
9447  */
9448  constrOid = CreateConstraintEntry(conname,
9449  RelationGetNamespace(rel),
9450  CONSTRAINT_FOREIGN,
9451  fkconstraint->deferrable,
9452  fkconstraint->initdeferred,
9453  fkconstraint->initially_valid,
9454  parentConstr,
9455  RelationGetRelid(rel),
9456  fkattnum,
9457  numfks,
9458  numfks,
9459  InvalidOid, /* not a domain constraint */
9460  indexOid,
9461  RelationGetRelid(pkrel),
9462  pkattnum,
9463  pfeqoperators,
9464  ppeqoperators,
9465  ffeqoperators,
9466  numfks,
9467  fkconstraint->fk_upd_action,
9468  fkconstraint->fk_del_action,
9469  fkconstraint->fk_matchtype,
9470  NULL, /* no exclusion constraint */
9471  NULL, /* no check constraint */
9472  NULL,
9473  conislocal, /* islocal */
9474  coninhcount, /* inhcount */
9475  connoinherit, /* conNoInherit */
9476  false); /* is_internal */
9477 
9478  ObjectAddressSet(address, ConstraintRelationId, constrOid);
9479 
9480  /*
9481  * Mark the child constraint as part of the parent constraint; it must not
9482  * be dropped on its own. (This constraint is deleted when the partition
9483  * is detached, but a special check needs to occur that the partition
9484  * contains no referenced values.)
9485  */
9486  if (OidIsValid(parentConstr))
9487  {
9488  ObjectAddress referenced;
9489 
9490  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9491  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
9492  }
9493 
9494  /* make new constraint visible, in case we add more */
9496 
9497  /*
9498  * If the referenced table is a plain relation, create the action triggers
9499  * that enforce the constraint.
9500  */
9501  if (pkrel->rd_rel->relkind == RELKIND_RELATION)
9502  {
9504  fkconstraint,
9505  constrOid, indexOid);
9506  }
9507 
9508  /*
9509  * If the referenced table is partitioned, recurse on ourselves to handle
9510  * each partition. We need one pg_constraint row created for each
9511  * partition in addition to the pg_constraint row for the parent table.
9512  */
9513  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9514  {
9515  PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
9516 
9517  for (int i = 0; i < pd->nparts; i++)
9518  {
9519  Relation partRel;
9520  AttrMap *map;
9521  AttrNumber *mapped_pkattnum;
9522  Oid partIndexId;
9523 
9524  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
9525 
9526  /*
9527  * Map the attribute numbers in the referenced side of the FK
9528  * definition to match the partition's column layout.
9529  */
9531  RelationGetDescr(pkrel));
9532  if (map)
9533  {
9534  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
9535  for (int j = 0; j < numfks; j++)
9536  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
9537  }
9538  else
9539  mapped_pkattnum = pkattnum;
9540 
9541  /* do the deed */
9542  partIndexId = index_get_partition(partRel, indexOid);
9543  if (!OidIsValid(partIndexId))
9544  elog(ERROR, "index for %u not found in partition %s",
9545  indexOid, RelationGetRelationName(partRel));
9546  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
9547  partIndexId, constrOid, numfks,
9548  mapped_pkattnum, fkattnum,
9549  pfeqoperators, ppeqoperators, ffeqoperators,
9550  old_check_ok);
9551 
9552  /* Done -- clean up (but keep the lock) */
9553  table_close(partRel, NoLock);
9554  if (map)
9555  {
9556  pfree(mapped_pkattnum);
9557  free_attrmap(map);
9558  }
9559  }
9560  }
9561 
9562  return address;
9563 }
#define NIL
Definition: pg_list.h:65
Oid index_get_partition(Relation partition, Oid indexId)
Definition: partition.c:175
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8772
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void free_attrmap(AttrMap *map)
Definition: attmap.c:57
#define RelationGetDescr(relation)
Definition: rel.h:503
char fk_matchtype
Definition: parsenodes.h:2300
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:50
int errcode(int sqlerrcode)
Definition: elog.c:698
bool initdeferred
Definition: parsenodes.h:2268
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
char * conname
Definition: parsenodes.h:2266
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
Definition: attmap.h:34
void pfree(void *pointer)
Definition: mcxt.c:1169
static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok)
Definition: tablecmds.c:9390
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:259
#define ERROR
Definition: elog.h:46
bool deferrable
Definition: parsenodes.h:2267
#define NoLock
Definition: lockdefs.h:34
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:72
#define RelationGetRelationName(relation)
Definition: rel.h:511
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:11285
void CommandCounterIncrement(void)
Definition: xact.c:1022
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2309
#define ereport(elevel,...)
Definition: elog.h:157
char fk_del_action
Definition: parsenodes.h:2302
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
AttrNumber * attnums
Definition: attmap.h:36
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
int i
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:477
List * fk_attrs
Definition: parsenodes.h:2298
char fk_upd_action
Definition: parsenodes.h:2301
#define RelationGetNamespace(relation)
Definition: rel.h:518

◆ addFkRecurseReferencing()

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

Definition at line 9595 of file tablecmds.c.

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

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferencing().

9600 {
9601  AssertArg(OidIsValid(parentConstr));
9602 
9603  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
9604  ereport(ERROR,
9605  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9606  errmsg("foreign key constraints are not supported on foreign tables")));
9607 
9608  /*
9609  * If the referencing relation is a plain table, add the check triggers to
9610  * it and, if necessary, schedule it to be checked in Phase 3.
9611  *
9612  * If the relation is partitioned, drill down to do it to its partitions.
9613  */
9614  if (rel->rd_rel->relkind == RELKIND_RELATION)
9615  {
9617  RelationGetRelid(pkrel),
9618  fkconstraint,
9619  parentConstr,
9620  indexOid);
9621 
9622  /*
9623  * Tell Phase 3 to check that the constraint is satisfied by existing
9624  * rows. We can skip this during table creation, when requested
9625  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
9626  * and when we're recreating a constraint following a SET DATA TYPE
9627  * operation that did not impugn its validity.
9628  */
9629  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
9630  {
9631  NewConstraint *newcon;
9632  AlteredTableInfo *tab;
9633 
9634  tab = ATGetQueueEntry(wqueue, rel);
9635 
9636  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9637  newcon->name = get_constraint_name(parentConstr);
9638  newcon->contype = CONSTR_FOREIGN;
9639  newcon->refrelid = RelationGetRelid(pkrel);
9640  newcon->refindid = indexOid;
9641  newcon->conid = parentConstr;
9642  newcon->qual = (Node *) fkconstraint;
9643 
9644  tab->constraints = lappend(tab->constraints, newcon);
9645  }
9646  }
9647  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9648  {
9649  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
9650 
9651  /*
9652  * Recurse to take appropriate action on each partition; either we
9653  * find an existing constraint to reparent to ours, or we create a new
9654  * one.
9655  */
9656  for (int i = 0; i < pd->nparts; i++)
9657  {
9658  Oid partitionId = pd->oids[i];
9659  Relation partition = table_open(partitionId, lockmode);
9660  List *partFKs;
9661  AttrMap *attmap;
9662  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
9663  bool attached;
9664  char *conname;
9665  Oid constrOid;
9666  ObjectAddress address,
9667  referenced;
9668  ListCell *cell;
9669 
9670  CheckTableNotInUse(partition, "ALTER TABLE");
9671 
9672  attmap = build_attrmap_by_name(RelationGetDescr(partition),
9673  RelationGetDescr(rel));
9674  for (int j = 0; j < numfks; j++)
9675  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
9676 
9677  /* Check whether an existing constraint can be repurposed */
9678  partFKs = copyObject(RelationGetFKeyList(partition));
9679  attached = false;
9680  foreach(cell, partFKs)
9681  {
9682  ForeignKeyCacheInfo *fk;
9683 
9684  fk = lfirst_node(ForeignKeyCacheInfo, cell);
9686  partitionId,
9687  parentConstr,
9688  numfks,
9689  mapped_fkattnum,
9690  pkattnum,
9691  pfeqoperators))
9692  {
9693  attached = true;
9694  break;
9695  }
9696  }
9697  if (attached)
9698  {
9699  table_close(partition, NoLock);
9700  continue;
9701  }
9702 
9703  /*
9704  * No luck finding a good constraint to reuse; create our own.
9705  */
9707  RelationGetRelid(partition),
9708  fkconstraint->conname))
9709  conname = ChooseConstraintName(RelationGetRelationName(partition),
9711  "fkey",
9712  RelationGetNamespace(partition), NIL);
9713  else
9714  conname = fkconstraint->conname;
9715  constrOid =
9716  CreateConstraintEntry(conname,
9717  RelationGetNamespace(partition),
9718  CONSTRAINT_FOREIGN,
9719  fkconstraint->deferrable,
9720  fkconstraint->initdeferred,
9721  fkconstraint->initially_valid,
9722  parentConstr,
9723  partitionId,
9724  mapped_fkattnum,
9725  numfks,
9726  numfks,
9727  InvalidOid,
9728  indexOid,
9729  RelationGetRelid(pkrel),
9730  pkattnum,
9731  pfeqoperators,
9732  ppeqoperators,
9733  ffeqoperators,
9734  numfks,
9735  fkconstraint->fk_upd_action,
9736  fkconstraint->fk_del_action,
9737  fkconstraint->fk_matchtype,
9738  NULL,
9739  NULL,
9740  NULL,
9741  false,
9742  1,
9743  false,
9744  false);
9745 
9746  /*
9747  * Give this constraint partition-type dependencies on the parent
9748  * constraint as well as the table.
9749  */
9750  ObjectAddressSet(address, ConstraintRelationId, constrOid);
9751  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9752  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
9753  ObjectAddressSet(referenced, RelationRelationId, partitionId);
9754  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
9755 
9756  /* Make all this visible before recursing */
9758 
9759  /* call ourselves to finalize the creation and we're done */
9760  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
9761  indexOid,
9762  constrOid,
9763  numfks,
9764  pkattnum,
9765  mapped_fkattnum,
9766  pfeqoperators,
9767  ppeqoperators,
9768  ffeqoperators,
9769  old_check_ok,
9770  lockmode);
9771 
9772  table_close(partition, NoLock);
9773  }
9774  }
9775 }
#define NIL
Definition: pg_list.h:65
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:11408
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
char * name
Definition: tablecmds.c:201
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8772
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define RelationGetDescr(relation)
Definition: rel.h:503
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1106
static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok, LOCKMODE lockmode)
Definition: tablecmds.c:9595
char fk_matchtype
Definition: parsenodes.h:2300
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:50
Node * qual
Definition: tablecmds.c:206
Definition: nodes.h:537
int errcode(int sqlerrcode)
Definition: elog.c:698
bool initdeferred
Definition: parsenodes.h:2268
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
char * conname
Definition: parsenodes.h:2266
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
List * constraints
Definition: tablecmds.c:174
Definition: attmap.h:34
static bool tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop)
Definition: tablecmds.c:10192
#define ERROR
Definition: elog.h:46
bool deferrable
Definition: parsenodes.h:2267
#define lfirst_node(type, lc)
Definition: pg_list.h:172
#define NoLock
Definition: lockdefs.h:34
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:72
#define RelationGetRelationName(relation)
Definition: rel.h:511
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5970
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3943
#define AssertArg(condition)
Definition: c.h:806
List * lappend(List *list, void *datum)
Definition: list.c:336
ConstrType contype
Definition: tablecmds.c:202
void * palloc0(Size size)
Definition: mcxt.c:1093
void CommandCounterIncrement(void)
Definition: xact.c:1022
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2309
#define ereport(elevel,...)
Definition: elog.h:157
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:174
char fk_del_action
Definition: parsenodes.h:2302
AttrNumber * attnums
Definition: attmap.h:36
#define INDEX_MAX_KEYS
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4567
int errmsg(const char *fmt,...)
Definition: elog.c:909
int i
#define copyObject(obj)
Definition: nodes.h:653
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
bool skip_validation
Definition: parsenodes.h:2308
#define RelationGetRelid(relation)
Definition: rel.h:477
List * fk_attrs
Definition: parsenodes.h:2298
char fk_upd_action
Definition: parsenodes.h:2301
#define RelationGetNamespace(relation)
Definition: rel.h:518

◆ alter_table_type_to_string()

static const char* alter_table_type_to_string ( AlterTableType  cmdtype)
static

Definition at line 6003 of file tablecmds.c.

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

6004 {
6005  switch (cmdtype)
6006  {
6007  case AT_AddColumn:
6008  case AT_AddColumnRecurse:
6009  case AT_AddColumnToView:
6010  return "ADD COLUMN";
6011  case AT_ColumnDefault:
6013  return "ALTER COLUMN ... SET DEFAULT";
6014  case AT_DropNotNull:
6015  return "ALTER COLUMN ... DROP NOT NULL";
6016  case AT_SetNotNull:
6017  return "ALTER COLUMN ... SET NOT NULL";
6018  case AT_DropExpression:
6019  return "ALTER COLUMN ... DROP EXPRESSION";
6020  case AT_CheckNotNull:
6021  return NULL; /* not real grammar */
6022  case AT_SetStatistics:
6023  return "ALTER COLUMN ... SET STATISTICS";
6024  case AT_SetOptions:
6025  return "ALTER COLUMN ... SET";
6026  case AT_ResetOptions:
6027  return "ALTER COLUMN ... RESET";
6028  case AT_SetStorage:
6029  return "ALTER COLUMN ... SET STORAGE";
6030  case AT_SetCompression:
6031  return "ALTER COLUMN ... SET COMPRESSION";
6032  case AT_DropColumn:
6033  case AT_DropColumnRecurse:
6034  return "DROP COLUMN";
6035  case AT_AddIndex:
6036  case AT_ReAddIndex:
6037  return NULL; /* not real grammar */
6038  case AT_AddConstraint:
6040  case AT_ReAddConstraint:
6042  case AT_AddIndexConstraint:
6043  return "ADD CONSTRAINT";
6044  case AT_AlterConstraint:
6045  return "ALTER CONSTRAINT";
6046  case AT_ValidateConstraint:
6048  return "VALIDATE CONSTRAINT";
6049  case AT_DropConstraint:
6051  return "DROP CONSTRAINT";
6052  case AT_ReAddComment:
6053  return NULL; /* not real grammar */
6054  case AT_AlterColumnType:
6055  return "ALTER COLUMN ... SET DATA TYPE";
6057  return "ALTER COLUMN ... OPTIONS";
6058  case AT_ChangeOwner:
6059  return "OWNER TO";
6060  case AT_ClusterOn:
6061  return "CLUSTER ON";
6062  case AT_DropCluster:
6063  return "SET WITHOUT CLUSTER";
6064  case AT_SetAccessMethod:
6065  return "SET ACCESS METHOD";
6066  case AT_SetLogged:
6067  return "SET LOGGED";
6068  case AT_SetUnLogged:
6069  return "SET UNLOGGED";
6070  case AT_DropOids:
6071  return "SET WITHOUT OIDS";
6072  case AT_SetTableSpace:
6073  return "SET TABLESPACE";
6074  case AT_SetRelOptions:
6075  return "SET";
6076  case AT_ResetRelOptions:
6077  return "RESET";
6078  case AT_ReplaceRelOptions:
6079  return NULL; /* not real grammar */
6080  case AT_EnableTrig:
6081  return "ENABLE TRIGGER";
6082  case AT_EnableAlwaysTrig:
6083  return "ENABLE ALWAYS TRIGGER";
6084  case AT_EnableReplicaTrig:
6085  return "ENABLE REPLICA TRIGGER";
6086  case AT_DisableTrig:
6087  return "DISABLE TRIGGER";
6088  case AT_EnableTrigAll:
6089  return "ENABLE TRIGGER ALL";
6090  case AT_DisableTrigAll:
6091  return "DISABLE TRIGGER ALL";
6092  case AT_EnableTrigUser:
6093  return "ENABLE TRIGGER USER";
6094  case AT_DisableTrigUser:
6095  return "DISABLE TRIGGER USER";
6096  case AT_EnableRule:
6097  return "ENABLE RULE";
6098  case AT_EnableAlwaysRule:
6099  return "ENABLE ALWAYS RULE";
6100  case AT_EnableReplicaRule:
6101  return "ENABLE REPLICA RULE";
6102  case AT_DisableRule:
6103  return "DISABLE RULE";
6104  case AT_AddInherit:
6105  return "INHERIT";
6106  case AT_DropInherit:
6107  return "NO INHERIT";
6108  case AT_AddOf:
6109  return "OF";
6110  case AT_DropOf:
6111  return "NOT OF";
6112  case AT_ReplicaIdentity:
6113  return "REPLICA IDENTITY";
6114  case AT_EnableRowSecurity:
6115  return "ENABLE ROW SECURITY";
6116  case AT_DisableRowSecurity:
6117  return "DISABLE ROW SECURITY";
6118  case AT_ForceRowSecurity:
6119  return "FORCE ROW SECURITY";
6120  case AT_NoForceRowSecurity:
6121  return "NO FORCE ROW SECURITY";
6122  case AT_GenericOptions:
6123  return "OPTIONS";
6124  case AT_AttachPartition:
6125  return "ATTACH PARTITION";
6126  case AT_DetachPartition:
6127  return "DETACH PARTITION";
6129  return "DETACH PARTITION ... FINALIZE";
6130  case AT_AddIdentity:
6131  return "ALTER COLUMN ... ADD IDENTITY";
6132  case AT_SetIdentity:
6133  return "ALTER COLUMN ... SET";
6134  case AT_DropIdentity:
6135  return "ALTER COLUMN ... DROP IDENTITY";
6136  case AT_ReAddStatistics:
6137  return NULL; /* not real grammar */
6138  }
6139 
6140  return NULL;
6141 }

◆ AlterIndexNamespaces()

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

Definition at line 16130 of file tablecmds.c.

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

Referenced by AlterTableNamespaceInternal().

16132 {
16133  List *indexList;
16134  ListCell *l;
16135 
16136  indexList = RelationGetIndexList(rel);
16137 
16138  foreach(l, indexList)
16139  {
16140  Oid indexOid = lfirst_oid(l);
16141  ObjectAddress thisobj;
16142 
16143  thisobj.classId = RelationRelationId;
16144  thisobj.objectId = indexOid;
16145  thisobj.objectSubId = 0;
16146 
16147  /*
16148  * Note: currently, the index will not have its own dependency on the
16149  * namespace, so we don't need to do changeDependencyFor(). There's no
16150  * row type in pg_type, either.
16151  *
16152  * XXX this objsMoved test may be pointless -- surely we have a single
16153  * dependency link from a relation to each index?
16154  */
16155  if (!object_address_present(&thisobj, objsMoved))
16156  {
16157  AlterRelationNamespaceInternal(classRel, indexOid,
16158  oldNspOid, newNspOid,
16159  false, objsMoved);
16160  add_exact_object_address(&thisobj, objsMoved);
16161  }
16162  }
16163 
16164  list_free(indexList);
16165 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2545
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2485
unsigned int Oid
Definition: postgres_ext.h:31
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16060
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4676
void list_free(List *list)
Definition: list.c:1391
Definition: pg_list.h:50
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ AlterRelationNamespaceInternal()

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

Definition at line 16060 of file tablecmds.c.

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

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

16064 {
16065  HeapTuple classTup;
16066  Form_pg_class classForm;
16067  ObjectAddress thisobj;
16068  bool already_done = false;
16069 
16070  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
16071  if (!HeapTupleIsValid(classTup))
16072  elog(ERROR, "cache lookup failed for relation %u", relOid);
16073  classForm = (Form_pg_class) GETSTRUCT(classTup);
16074 
16075  Assert(classForm->relnamespace == oldNspOid);
16076 
16077  thisobj.classId = RelationRelationId;
16078  thisobj.objectId = relOid;
16079  thisobj.objectSubId = 0;
16080 
16081  /*
16082  * If the object has already been moved, don't move it again. If it's
16083  * already in the right place, don't move it, but still fire the object
16084  * access hook.
16085  */
16086  already_done = object_address_present(&thisobj, objsMoved);
16087  if (!already_done && oldNspOid != newNspOid)
16088  {
16089  /* check for duplicate name (more friendly than unique-index failure) */
16090  if (get_relname_relid(NameStr(classForm->relname),
16091  newNspOid) != InvalidOid)
16092  ereport(ERROR,
16093  (errcode(ERRCODE_DUPLICATE_TABLE),
16094  errmsg("relation \"%s\" already exists in schema \"%s\"",
16095  NameStr(classForm->relname),
16096  get_namespace_name(newNspOid))));
16097 
16098  /* classTup is a copy, so OK to scribble on */
16099  classForm->relnamespace = newNspOid;
16100 
16101  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
16102 
16103  /* Update dependency on schema if caller said so */
16104  if (hasDependEntry &&
16105  changeDependencyFor(RelationRelationId,
16106  relOid,
16107  NamespaceRelationId,
16108  oldNspOid,
16109  newNspOid) != 1)
16110  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
16111  NameStr(classForm->relname));
16112  }
16113  if (!already_done)
16114  {
16115  add_exact_object_address(&thisobj, objsMoved);
16116 
16117  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
16118  }
16119 
16120  heap_freetuple(classTup);
16121 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2545
int errcode(int sqlerrcode)
Definition: elog.c:698
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2485
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1856
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
int errmsg(const char *fmt,...)
Definition: elog.c:909
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:399
#define elog(elevel,...)
Definition: elog.h:232
#define NameStr(name)
Definition: c.h:681

◆ AlterSeqNamespaces()

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

Definition at line 16175 of file tablecmds.c.

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

Referenced by AlterTableNamespaceInternal().

16178 {
16179  Relation depRel;
16180  SysScanDesc scan;
16181  ScanKeyData key[2];
16182  HeapTuple tup;
16183 
16184  /*
16185  * SERIAL sequences are those having an auto dependency on one of the
16186  * table's columns (we don't care *which* column, exactly).
16187  */
16188  depRel = table_open(DependRelationId, AccessShareLock);
16189 
16190  ScanKeyInit(&key[0],
16191  Anum_pg_depend_refclassid,
16192  BTEqualStrategyNumber, F_OIDEQ,
16193  ObjectIdGetDatum(RelationRelationId));
16194  ScanKeyInit(&key[1],
16195  Anum_pg_depend_refobjid,
16196  BTEqualStrategyNumber, F_OIDEQ,
16198  /* we leave refobjsubid unspecified */
16199 
16200  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
16201  NULL, 2, key);
16202 
16203  while (HeapTupleIsValid(tup = systable_getnext(scan)))
16204  {
16205  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
16206  Relation seqRel;
16207 
16208  /* skip dependencies other than auto dependencies on columns */
16209  if (depForm->refobjsubid == 0 ||
16210  depForm->classid != RelationRelationId ||
16211  depForm->objsubid != 0 ||
16212  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
16213  continue;
16214 
16215  /* Use relation_open just in case it's an index */
16216  seqRel = relation_open(depForm->objid, lockmode);
16217 
16218  /* skip non-sequence relations */
16219  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
16220  {
16221  /* No need to keep the lock */
16222  relation_close(seqRel, lockmode);
16223  continue;
16224  }
16225 
16226  /* Fix the pg_class and pg_depend entries */
16227  AlterRelationNamespaceInternal(classRel, depForm->objid,
16228  oldNspOid, newNspOid,
16229  true, objsMoved);
16230 
16231  /*
16232  * Sequences used to have entries in pg_type, but no longer do. If we
16233  * ever re-instate that, we'll need to move the pg_type entry to the
16234  * new namespace, too (using AlterTypeNamespaceInternal).
16235  */
16236  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
16237 
16238  /* Now we can close it. Keep the lock till end of transaction. */
16239  relation_close(seqRel, NoLock);
16240  }
16241 
16242  systable_endscan(scan);
16243 
16245 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:595
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
#define RelationGetForm(relation)
Definition: rel.h:471
#define AccessShareLock
Definition: lockdefs.h:36
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:383
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:502
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:804
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16060
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:477
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ AlterTable()

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

Definition at line 4027 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

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

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4101 of file tablecmds.c.

References AccessExclusiveLock, AccessShareLock, AlterTableGetRelOptionsLockLevel(), AT_AddColumn, AT_AddColumnToView, AT_AddConstraint, AT_AddConstraintRecurse, AT_AddIdentity, AT_AddIndex, AT_AddIndexConstraint, AT_AddInherit, AT_AddOf, AT_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().

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

◆ AlterTableInternal()

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

Definition at line 4056 of file tablecmds.c.

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

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

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3971 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

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

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 14065 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

14066 {
14067  List *relations = NIL;
14068  ListCell *l;
14069  ScanKeyData key[1];
14070  Relation rel;
14071  TableScanDesc scan;
14072  HeapTuple tuple;
14073  Oid orig_tablespaceoid;
14074  Oid new_tablespaceoid;
14075  List *role_oids = roleSpecsToIds(stmt->roles);
14076 
14077  /* Ensure we were not asked to move something we can't */
14078  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
14079  stmt->objtype != OBJECT_MATVIEW)
14080  ereport(ERROR,
14081  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14082  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
14083 
14084  /* Get the orig and new tablespace OIDs */
14085  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
14086  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
14087 
14088  /* Can't move shared relations in to or out of pg_global */
14089  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
14090  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
14091  new_tablespaceoid == GLOBALTABLESPACE_OID)
14092  ereport(ERROR,
14093  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14094  errmsg("cannot move relations in to or out of pg_global tablespace")));
14095 
14096  /*
14097  * Must have CREATE rights on the new tablespace, unless it is the
14098  * database default tablespace (which all users implicitly have CREATE
14099  * rights on).
14100  */
14101  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
14102  {
14103  AclResult aclresult;
14104 
14105  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
14106  ACL_CREATE);
14107  if (aclresult != ACLCHECK_OK)
14108  aclcheck_error(aclresult, OBJECT_TABLESPACE,
14109  get_tablespace_name(new_tablespaceoid));
14110  }
14111 
14112  /*
14113  * Now that the checks are done, check if we should set either to
14114  * InvalidOid because it is our database's default tablespace.
14115  */
14116  if (orig_tablespaceoid == MyDatabaseTableSpace)
14117  orig_tablespaceoid = InvalidOid;
14118 
14119  if (new_tablespaceoid == MyDatabaseTableSpace)
14120  new_tablespaceoid = InvalidOid;
14121 
14122  /* no-op */
14123  if (orig_tablespaceoid == new_tablespaceoid)
14124  return new_tablespaceoid;
14125 
14126  /*
14127  * Walk the list of objects in the tablespace and move them. This will
14128  * only find objects in our database, of course.
14129  */
14130  ScanKeyInit(&key[0],
14131  Anum_pg_class_reltablespace,
14132  BTEqualStrategyNumber, F_OIDEQ,
14133  ObjectIdGetDatum(orig_tablespaceoid));
14134 
14135  rel = table_open(RelationRelationId, AccessShareLock);
14136  scan = table_beginscan_catalog(rel, 1, key);
14137  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
14138  {
14139  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
14140  Oid relOid = relForm->oid;
14141 
14142  /*
14143  * Do not move objects in pg_catalog as part of this, if an admin
14144  * really wishes to do so, they can issue the individual ALTER
14145  * commands directly.
14146  *
14147  * Also, explicitly avoid any shared tables, temp tables, or TOAST
14148  * (TOAST will be moved with the main table).
14149  */
14150  if (IsCatalogNamespace(relForm->relnamespace) ||
14151  relForm->relisshared ||
14152  isAnyTempNamespace(relForm->relnamespace) ||
14153  IsToastNamespace(relForm->relnamespace))
14154  continue;
14155 
14156  /* Only move the object type requested */
14157  if ((stmt->objtype == OBJECT_TABLE &&
14158  relForm->relkind != RELKIND_RELATION &&
14159  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
14160  (stmt->objtype == OBJECT_INDEX &&
14161  relForm->relkind != RELKIND_INDEX &&
14162  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
14163  (stmt->objtype == OBJECT_MATVIEW &&
14164  relForm->relkind != RELKIND_MATVIEW))
14165  continue;
14166 
14167  /* Check if we are only moving objects owned by certain roles */
14168  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
14169  continue;
14170 
14171  /*
14172  * Handle permissions-checking here since we are locking the tables
14173  * and also to avoid doing a bunch of work only to fail part-way. Note
14174  * that permissions will also be checked by AlterTableInternal().
14175  *
14176  * Caller must be considered an owner on the table to move it.
14177  */
14178  if (!pg_class_ownercheck(relOid, GetUserId()))
14180  NameStr(relForm->relname));
14181 
14182  if (stmt->nowait &&
14184  ereport(ERROR,
14185  (errcode(ERRCODE_OBJECT_IN_USE),
14186  errmsg("aborting because lock on relation \"%s.%s\" is not available",
14187  get_namespace_name(relForm->relnamespace),
14188  NameStr(relForm->relname))));
14189  else
14191 
14192  /* Add to our list of objects to move */
14193  relations = lappend_oid(relations, relOid);
14194  }
14195 
14196  table_endscan(scan);
14198 
14199  if (relations == NIL)
14200  ereport(NOTICE,
14201  (errcode(ERRCODE_NO_DATA_FOUND),
14202  errmsg("no matching relations in tablespace \"%s\" found",
14203  orig_tablespaceoid == InvalidOid ? "(database default)" :
14204  get_tablespace_name(orig_tablespaceoid))));
14205 
14206  /* Everything is locked, loop through and move all of the relations. */
14207  foreach(l, relations)
14208  {
14209  List *cmds = NIL;
14211 
14212  cmd->subtype = AT_SetTableSpace;
14213  cmd->name = stmt->new_tablespacename;
14214 
14215  cmds = lappend(cmds, cmd);
14216 
14218  /* OID is set by AlterTableInternal */
14219  AlterTableInternal(lfirst_oid(l), cmds, false);
14221  }
14222 
14223  return new_tablespaceoid;
14224 }
#define NIL
Definition: pg_list.h:65
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:152
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1427
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4768
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
Oid GetUserId(void)
Definition: miscinit.c:495
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1974
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:537
int errcode(int sqlerrcode)
Definition: elog.c:698
AlterTableType subtype
Definition: parsenodes.h:1962
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:201
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
#define OidIsValid(objectId)
Definition: c.h:710
Oid MyDatabaseTableSpace
Definition: globals.c:90
void EventTriggerAlterTableStart(Node *parsetree)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3308
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define ACL_CREATE
Definition: parsenodes.h:92
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3316
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1340
List * lappend(List *list, void *datum)
Definition: list.c:336
AclResult
Definition: acl.h:177
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:585
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1376
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:689
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4818
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:183
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:991
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:4056
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:909
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1473
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:681
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3240
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:109
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:171
void EventTriggerAlterTableEnd(void)

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 15950 of file tablecmds.c.

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

Referenced by ExecAlterObjectSchemaStmt().

15951 {
15952  Relation rel;
15953  Oid relid;
15954  Oid oldNspOid;
15955  Oid nspOid;
15956  RangeVar *newrv;
15957  ObjectAddresses *objsMoved;
15958  ObjectAddress myself;
15959 
15961  stmt->missing_ok ? RVR_MISSING_OK : 0,
15963  (void *) stmt);
15964 
15965  if (!OidIsValid(relid))
15966  {
15967  ereport(NOTICE,
15968  (errmsg("relation \"%s\" does not exist, skipping",
15969  stmt->relation->relname)));
15970  return InvalidObjectAddress;
15971  }
15972 
15973  rel = relation_open(relid, NoLock);
15974 
15975  oldNspOid = RelationGetNamespace(rel);
15976 
15977  /* If it's an owned sequence, disallow moving it by itself. */
15978  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
15979  {
15980  Oid tableId;
15981  int32 colId;
15982 
15983  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
15984  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
15985  ereport(ERROR,
15986  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15987  errmsg("cannot move an owned sequence into another schema"),
15988  errdetail("Sequence \"%s\" is linked to table \"%s\".",
15990  get_rel_name(tableId))));
15991  }
15992 
15993  /* Get and lock schema OID and check its permissions. */
15994  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
15995  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
15996 
15997  /* common checks on switching namespaces */
15998  CheckSetNamespace(oldNspOid, nspOid);
15999 
16000  objsMoved = new_object_addresses();
16001  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
16002  free_object_addresses(objsMoved);
16003 
16004  ObjectAddressSet(myself, RelationRelationId, relid);
16005 
16006  if (oldschema)
16007  *oldschema = oldNspOid;
16008 
16009  /* close rel, but keep lock until commit */
16010  relation_close(rel, NoLock);
16011 
16012  return myself;
16013 }
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:770
int errcode(int sqlerrcode)
Definition: elog.c:698
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2430
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2725
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
signed int int32
Definition: c.h:429
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:46
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16021
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:16574
int errdetail(const char *fmt,...)
Definition: elog.c:1042
#define RelationGetRelationName(relation)
Definition: rel.h:511
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:237
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3012
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:535
#define ereport(elevel,...)
Definition: elog.h:157
#define NOTICE
Definition: elog.h:37
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:909
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1899
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:422
#define RelationGetNamespace(relation)
Definition: rel.h:518

◆ AlterTableNamespaceInternal()

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

Definition at line 16021 of file tablecmds.c.

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

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

16023 {
16024  Relation classRel;
16025 
16026  Assert(objsMoved != NULL);
16027 
16028  /* OK, modify the pg_class row and pg_depend entry */
16029  classRel = table_open(RelationRelationId, RowExclusiveLock);
16030 
16031  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
16032  nspOid, true, objsMoved);
16033 
16034  /* Fix the table's row type too, if it has one */
16035  if (OidIsValid(rel->rd_rel->reltype))
16036  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
16037  nspOid, false, false, objsMoved);
16038 
16039  /* Fix other dependent stuff */
16040  if (rel->rd_rel->relkind == RELKIND_RELATION ||
16041  rel->rd_rel->relkind == RELKIND_MATVIEW ||
16042  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16043  {
16044  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
16045  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
16046  objsMoved, AccessExclusiveLock);
16047  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
16048  false, objsMoved);
16049  }
16050 
16051  table_close(classRel, RowExclusiveLock);
16052 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3955
Form_pg_class rd_rel
Definition: rel.h:109
#define OidIsValid(objectId)
Definition: c.h:710
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16130
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:16175
#define RowExclusiveLock
Definition: lockdefs.h:38
#define Assert(condition)
Definition: c.h:804
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16060
#define AccessExclusiveLock
Definition: lockdefs.h:45
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:477

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

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

Referenced by ATExecAddConstraint(), and DetachAddConstraintIfNeeded().

8817 {
8818  List *newcons;
8819  ListCell *lcon;
8820  List *children;
8821  ListCell *child;
8823 
8824  /* At top level, permission check was done in ATPrepCmd, else do it */
8825  if (recursing)
8827 
8828  /*
8829  * Call AddRelationNewConstraints to do the work, making sure it works on
8830  * a copy of the Constraint so transformExpr can't modify the original. It
8831  * returns a list of cooked constraints.
8832  *
8833  * If the constraint ends up getting merged with a pre-existing one, it's
8834  * omitted from the returned list, which is what we want: we do not need
8835  * to do any validation work. That can only happen at child tables,
8836  * though, since we disallow merging at the top level.
8837  */
8838  newcons = AddRelationNewConstraints(rel, NIL,
8839  list_make1(copyObject(constr)),
8840  recursing | is_readd, /* allow_merge */
8841  !recursing, /* is_local */
8842  is_readd, /* is_internal */
8843  NULL); /* queryString not available
8844  * here */
8845 
8846  /* we don't expect more than one constraint here */
8847  Assert(list_length(newcons) <= 1);
8848 
8849  /* Add each to-be-validated constraint to Phase 3's queue */
8850  foreach(lcon, newcons)
8851  {
8852  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
8853 
8854  if (!ccon->skip_validation)
8855  {
8856  NewConstraint *newcon;
8857 
8858  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
8859  newcon->name = ccon->name;
8860  newcon->contype = ccon->contype;
8861  newcon->qual = ccon->expr;
8862 
8863  tab->constraints = lappend(tab->constraints, newcon);
8864  }
8865 
8866  /* Save the actually assigned name if it was defaulted */
8867  if (constr->conname == NULL)
8868  constr->conname = ccon->name;
8869 
8870  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
8871  }
8872 
8873  /* At this point we must have a locked-down name to use */
8874  Assert(constr->conname != NULL);
8875 
8876  /* Advance command counter in case same table is visited multiple times */
8878 
8879  /*
8880  * If the constraint got merged with an existing constraint, we're done.
8881  * We mustn't recurse to child tables in this case, because they've
8882  * already got the constraint, and visiting them again would lead to an
8883  * incorrect value for coninhcount.
8884  */
8885  if (newcons == NIL)
8886  return address;
8887 
8888  /*
8889  * If adding a NO INHERIT constraint, no need to find our children.
8890  */
8891  if (constr->is_no_inherit)
8892  return address;
8893 
8894  /*
8895  * Propagate to children as appropriate. Unlike most other ALTER
8896  * routines, we have to do this one level of recursion at a time; we can't
8897  * use find_all_inheritors to do it in one pass.
8898  */
8899  children =
8901 
8902  /*
8903  * Check if ONLY was specified with ALTER TABLE. If so, allow the
8904  * constraint creation only if there are no children currently. Error out
8905  * otherwise.
8906  */
8907  if (!recurse && children != NIL)
8908  ereport(ERROR,
8909  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8910  errmsg("constraint must be added to child tables too")));
8911 
8912  foreach(child, children)
8913  {
8914  Oid childrelid = lfirst_oid(child);
8915  Relation childrel;
8916  AlteredTableInfo *childtab;
8917 
8918  /* find_inheritance_children already got lock */
8919  childrel = table_open(childrelid, NoLock);
8920  CheckTableNotInUse(childrel, "ALTER TABLE");
8921 
8922  /* Find or create work queue entry for this table */
8923  childtab = ATGetQueueEntry(wqueue, childrel);
8924 
8925  /* Recurse to child */
8926  ATAddCheckConstraint(wqueue, childtab, childrel,
8927  constr, recurse, true, is_readd, lockmode);
8928 
8929  table_close(childrel, NoLock);
8930  }
8931 
8932  return address;
8933 }
#define NIL
Definition: pg_list.h:65
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2581
char * name
Definition: tablecmds.c:201
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Node * qual
Definition: tablecmds.c:206
int errcode(int sqlerrcode)
Definition: elog.c:698
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:8814
char * conname
Definition: parsenodes.h:2266
unsigned int Oid
Definition: postgres_ext.h:31
#define ATT_TABLE
Definition: tablecmds.c:306
List * constraints
Definition: tablecmds.c:174
#define list_make1(x1)
Definition: pg_list.h:206
static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
Definition: tablecmds.c:6151
#define ERROR
Definition: elog.h:46
#define NoLock
Definition: lockdefs.h:34
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5970
bool skip_validation
Definition: heap.h:42
ConstrType contype
Definition: heap.h:37
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3943
List * lappend(List *list, void *datum)
Definition: list.c:336
ConstrType contype
Definition: tablecmds.c:202
void * palloc0(Size size)
Definition: mcxt.c:1093
void CommandCounterIncrement(void)
Definition: xact.c:1022
bool is_no_inherit
Definition: parsenodes.h:2272
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:59
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:909
Oid conoid
Definition: heap.h:38
Node * expr
Definition: heap.h:41
#define copyObject(obj)
Definition: nodes.h:653
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:311
char * name
Definition: heap.h:39
#define RelationGetRelid(relation)
Definition: rel.h:477
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ ATAddForeignKeyConstraint()

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

Definition at line 8951 of file tablecmds.c.

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

Referenced by ATExecAddConstraint().

8954 {
8955  Relation pkrel;
8956  int16 pkattnum[INDEX_MAX_KEYS];
8957  int16 fkattnum[INDEX_MAX_KEYS];
8958  Oid pktypoid[INDEX_MAX_KEYS];
8959  Oid fktypoid[INDEX_MAX_KEYS];
8960  Oid opclasses[INDEX_MAX_KEYS];
8961  Oid pfeqoperators[INDEX_MAX_KEYS];
8962  Oid ppeqoperators[INDEX_MAX_KEYS];
8963  Oid ffeqoperators[INDEX_MAX_KEYS];
8964  int i;
8965  int numfks,
8966  numpks;
8967  Oid indexOid;
8968  bool old_check_ok;
8969  ObjectAddress address;
8970  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
8971 
8972  /*
8973  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
8974  * delete rows out from under us.
8975  */
8976  if (OidIsValid(fkconstraint->old_pktable_oid))
8977  pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
8978  else
8979  pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
8980 
8981  /*
8982  * Validity checks (permission checks wait till we have the column
8983  * numbers)
8984  */
8985  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8986  {
8987  if (!recurse)
8988  ereport(ERROR,
8989  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8990  errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
8992  RelationGetRelationName(pkrel))));
8993  if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
8994  ereport(ERROR,
8995  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8996  errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
8998  RelationGetRelationName(pkrel)),
8999  errdetail("This feature is not yet supported on partitioned tables.")));
9000  }
9001 
9002  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9003  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9004  ereport(ERROR,
9005  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9006  errmsg("referenced relation \"%s\" is not a table",
9007  RelationGetRelationName(pkrel))));
9008 
9009  if (!allowSystemTableMods && IsSystemRelation(pkrel))
9010  ereport(ERROR,
9011  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
9012  errmsg("permission denied: \"%s\" is a system catalog",
9013  RelationGetRelationName(pkrel))));
9014 
9015  /*
9016  * References from permanent or unlogged tables to temp tables, and from
9017  * permanent tables to unlogged tables, are disallowed because the
9018  * referenced data can vanish out from under us. References from temp
9019  * tables to any other table type are also disallowed, because other
9020  * backends might need to run the RI triggers on the perm table, but they
9021  * can't reliably see tuples in the local buffers of other backends.
9022  */
9023  switch (rel->rd_rel->relpersistence)
9024  {
9025  case RELPERSISTENCE_PERMANENT:
9026  if (!RelationIsPermanent(pkrel))
9027  ereport(ERROR,
9028  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9029  errmsg("constraints on permanent tables may reference only permanent tables")));
9030  break;
9031  case RELPERSISTENCE_UNLOGGED:
9032  if (!RelationIsPermanent(pkrel)
9033  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
9034  ereport(ERROR,
9035  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9036  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
9037  break;
9038  case RELPERSISTENCE_TEMP:
9039  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
9040  ereport(ERROR,
9041  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9042  errmsg("constraints on temporary tables may reference only temporary tables")));
9043  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
9044  ereport(ERROR,
9045  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
9046  errmsg("constraints on temporary tables must involve temporary tables of this session")));
9047  break;
9048  }
9049 
9050  /*
9051  * Look up the referencing attributes to make sure they exist, and record
9052  * their attnums and type OIDs.
9053  */
9054  MemSet(pkattnum, 0, sizeof(pkattnum));
9055  MemSet(fkattnum, 0, sizeof(fkattnum));
9056  MemSet(pktypoid, 0, sizeof(pktypoid));
9057  MemSet(fktypoid, 0, sizeof(fktypoid));
9058  MemSet(opclasses, 0, sizeof(opclasses));
9059  MemSet(pfeqoperators, 0, sizeof(pfeqoperators));
9060  MemSet(ppeqoperators, 0, sizeof(ppeqoperators));
9061  MemSet(ffeqoperators, 0, sizeof(ffeqoperators));
9062 
9064  fkconstraint->fk_attrs,
9065  fkattnum, fktypoid);
9066 
9067  /*
9068  * If the attribute list for the referenced table was omitted, lookup the
9069  * definition of the primary key and use it. Otherwise, validate the
9070  * supplied attribute list. In either case, discover the index OID and
9071  * index opclasses, and the attnums and type OIDs of the attributes.
9072  */
9073  if (fkconstraint->pk_attrs == NIL)
9074  {
9075  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
9076  &fkconstraint->pk_attrs,
9077  pkattnum, pktypoid,
9078  opclasses);
9079  }
9080  else
9081  {
9082  numpks = transformColumnNameList(RelationGetRelid(pkrel),
9083  fkconstraint->pk_attrs,
9084  pkattnum, pktypoid);
9085  /* Look for an index matching the column list */
9086  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
9087  opclasses);
9088  }
9089 
9090  /*
9091  * Now we can check permissions.
9092  */
9093  checkFkeyPermissions(pkrel, pkattnum, numpks);
9094 
9095  /*
9096  * Check some things for generated columns.
9097  */
9098  for (i = 0; i < numfks; i++)
9099  {
9100  char attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
9101 
9102  if (attgenerated)
9103  {
9104  /*
9105  * Check restrictions on UPDATE/DELETE actions, per SQL standard
9106  */
9107  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
9108  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
9109  fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
9110  ereport(ERROR,
9111  (errcode(ERRCODE_SYNTAX_ERROR),
9112  errmsg("invalid %s action for foreign key constraint containing generated column",
9113  "ON UPDATE")));
9114  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
9115  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
9116  ereport(ERROR,
9117  (errcode(ERRCODE_SYNTAX_ERROR),
9118  errmsg("invalid %s action for foreign key constraint containing generated column",
9119  "ON DELETE")));
9120  }
9121  }
9122 
9123  /*
9124  * Look up the equality operators to use in the constraint.
9125  *
9126  * Note that we have to be careful about the difference between the actual
9127  * PK column type and the opclass' declared input type, which might be
9128  * only binary-compatible with it. The declared opcintype is the right
9129  * thing to probe pg_amop with.
9130  */
9131  if (numfks != numpks)
9132  ereport(ERROR,
9133  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
9134  errmsg("number of referencing and referenced columns for foreign key disagree")));
9135 
9136  /*
9137  * On the strength of a previous constraint, we might avoid scanning
9138  * tables to validate this one. See below.
9139  */
9140  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
9141  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
9142 
9143  for (i = 0; i < numpks; i++)
9144  {
9145  Oid pktype = pktypoid[i];
9146  Oid fktype = fktypoid[i];
9147  Oid fktyped;
9148  HeapTuple cla_ht;
9149  Form_pg_opclass cla_tup;
9150  Oid amid;
9151  Oid opfamily;
9152  Oid opcintype;
9153  Oid pfeqop;
9154  Oid ppeqop;
9155  Oid ffeqop;
9156  int16 eqstrategy;
9157  Oid pfeqop_right;
9158 
9159  /* We need several fields out of the pg_opclass entry */
9160  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
9161  if (!HeapTupleIsValid(cla_ht))
9162  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
9163  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
9164  amid = cla_tup->opcmethod;
9165  opfamily = cla_tup->opcfamily;
9166  opcintype = cla_tup->opcintype;
9167  ReleaseSysCache(cla_ht);
9168 
9169  /*
9170  * Check it's a btree; currently this can never fail since no other
9171  * index AMs support unique indexes. If we ever did have other types
9172  * of unique indexes, we'd need a way to determine which operator
9173  * strategy number is equality. (Is it reasonable to insist that
9174  * every such index AM use btree's number for equality?)
9175  */
9176  if (amid != BTREE_AM_OID)
9177  elog(ERROR, "only b-tree indexes are supported for foreign keys");
9178  eqstrategy = BTEqualStrategyNumber;
9179 
9180  /*
9181  * There had better be a primary equality operator for the index.
9182  * We'll use it for PK = PK comparisons.
9183  */
9184  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
9185  eqstrategy);
9186 
9187  if (!OidIsValid(ppeqop))
9188  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
9189  eqstrategy, opcintype, opcintype, opfamily);
9190 
9191  /*
9192  * Are there equality operators that take exactly the FK type? Assume
9193  * we should look through any domain here.
9194  */
9195  fktyped = getBaseType(fktype);
9196 
9197  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
9198  eqstrategy);
9199  if (OidIsValid(pfeqop))
9200  {
9201  pfeqop_right = fktyped;
9202  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
9203  eqstrategy);
9204  }
9205  else
9206  {
9207  /* keep compiler quiet */
9208  pfeqop_right = InvalidOid;
9209  ffeqop = InvalidOid;
9210  }
9211 
9212  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9213  {
9214  /*
9215  * Otherwise, look for an implicit cast from the FK type to the
9216  * opcintype, and if found, use the primary equality operator.
9217  * This is a bit tricky because opcintype might be a polymorphic
9218  * type such as ANYARRAY or ANYENUM; so what we have to test is
9219  * whether the two actual column types can be concurrently cast to
9220  * that type. (Otherwise, we'd fail to reject combinations such
9221  * as int[] and point[].)
9222  */
9223  Oid input_typeids[2];
9224  Oid target_typeids[2];
9225 
9226  input_typeids[0] = pktype;
9227  input_typeids[1] = fktype;
9228  target_typeids[0] = opcintype;
9229  target_typeids[1] = opcintype;
9230  if (can_coerce_type(2, input_typeids, target_typeids,
9232  {
9233  pfeqop = ffeqop = ppeqop;
9234  pfeqop_right = opcintype;
9235  }
9236  }
9237 
9238  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
9239  ereport(ERROR,
9240  (errcode(ERRCODE_DATATYPE_MISMATCH),
9241  errmsg("foreign key constraint \"%s\" cannot be implemented",
9242  fkconstraint->conname),
9243  errdetail("Key columns \"%s\" and \"%s\" "
9244  "are of incompatible types: %s and %s.",
9245  strVal(list_nth(fkconstraint->fk_attrs, i)),
9246  strVal(list_nth(fkconstraint->pk_attrs, i)),
9247  format_type_be(fktype),
9248  format_type_be(pktype))));
9249 
9250  if (old_check_ok)
9251  {
9252  /*
9253  * When a pfeqop changes, revalidate the constraint. We could
9254  * permit intra-opfamily changes, but that adds subtle complexity
9255  * without any concrete benefit for core types. We need not
9256  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
9257  */
9258  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
9259  old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
9260  old_pfeqop_item);
9261  }
9262  if (old_check_ok)
9263  {
9264  Oid old_fktype;
9265  Oid new_fktype;
9266  CoercionPathType old_pathtype;
9267  CoercionPathType new_pathtype;
9268  Oid old_castfunc;
9269  Oid new_castfunc;
9271  fkattnum[i] - 1);
9272 
9273  /*
9274  * Identify coercion pathways from each of the old and new FK-side
9275  * column types to the right (foreign) operand type of the pfeqop.
9276  * We may assume that pg_constraint.conkey is not changing.
9277  */
9278  old_fktype = attr->atttypid;
9279  new_fktype = fktype;
9280  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
9281  &old_castfunc);
9282  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
9283  &new_castfunc);
9284 
9285  /*
9286  * Upon a change to the cast from the FK column to its pfeqop
9287  * operand, revalidate the constraint. For this evaluation, a
9288  * binary coercion cast is equivalent to no cast at all. While
9289  * type implementors should design implicit casts with an eye
9290  * toward consistency of operations like equality, we cannot
9291  * assume here that they have done so.
9292  *
9293  * A function with a polymorphic argument could change behavior
9294  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
9295  * when the cast destination is polymorphic, we only avoid
9296  * revalidation if the input type has not changed at all. Given
9297  * just the core data types and operator classes, this requirement
9298  * prevents no would-be optimizations.
9299  *
9300  * If the cast converts from a base type to a domain thereon, then
9301  * that domain type must be the opcintype of the unique index.
9302  * Necessarily, the primary key column must then be of the domain
9303  * type. Since the constraint was previously valid, all values on
9304  * the foreign side necessarily exist on the primary side and in
9305  * turn conform to the domain. Consequently, we need not treat
9306  * domains specially here.
9307  *
9308  * Since we require that all collations share the same notion of
9309  * equality (which they do, because texteq reduces to bitwise
9310  * equality), we don't compare collation here.
9311  *
9312  * We need not directly consider the PK type. It's necessarily
9313  * binary coercible to the opcintype of the unique index column,
9314  * and ri_triggers.c will only deal with PK datums in terms of
9315  * that opcintype. Changing the opcintype also changes pfeqop.
9316  */
9317  old_check_ok = (new_pathtype == old_pathtype &&
9318  new_castfunc == old_castfunc &&
9319  (!IsPolymorphicType(pfeqop_right) ||
9320  new_fktype == old_fktype));
9321  }
9322 
9323  pfeqoperators[i] = pfeqop;
9324  ppeqoperators[i] = ppeqop;
9325  ffeqoperators[i] = ffeqop;
9326  }
9327 
9328  /*
9329  * Create all the constraint and trigger objects, recursing to partitions
9330  * as necessary. First handle the referenced side.
9331  */
9332  address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
9333  indexOid,
9334  InvalidOid, /* no parent constraint */
9335  numfks,
9336  pkattnum,
9337  fkattnum,
9338  pfeqoperators,
9339  ppeqoperators,
9340  ffeqoperators,
9341  old_check_ok);
9342 
9343  /* Now handle the referencing side. */
9344  addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
9345  indexOid,
9346  address.objectId,
9347  numfks,
9348  pkattnum,
9349  fkattnum,
9350  pfeqoperators,
9351  ppeqoperators,
9352  ffeqoperators,
9353  old_check_ok,
9354  lockmode);
9355 
9356  /*
9357  * Done. Close pk table, but keep lock until we've committed.
9358  */
9359  table_close(pkrel, NoLock);
9360 
9361  return address;
9362 }
signed short int16
Definition: c.h:428
#define NIL
Definition: pg_list.h:65
#define RelationIsPermanent(relation)
Definition: rel.h:590
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
List * old_conpfeqop
Definition: parsenodes.h:2303
bool IsSystemRelation(Relation relation)
Definition: catalog.c:74
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
#define RelationGetDescr(relation)
Definition: rel.h:503
static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok, LOCKMODE lockmode)
Definition: tablecmds.c:9595
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
bool can_coerce_type(int nargs, const Oid *input_typeids, const Oid *target_typeids, CoercionContext ccontext)
Definition: parse_coerce.c:556
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2253
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids)
Definition: tablecmds.c:10798
bool rd_islocaltemp
Definition: rel.h:60
#define strVal(v)
Definition: value.h:65
int errcode(int sqlerrcode)
Definition: elog.c:698
#define MemSet(start, val, len)
Definition: c.h:1008
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
List * pk_attrs
Definition: parsenodes.h:2299
char * conname
Definition: parsenodes.h:2266
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:11110
#define OidIsValid(objectId)
Definition: c.h:710
CoercionPathType
Definition: parse_coerce.h:24
static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok)
Definition: tablecmds.c:9390
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
TupleDesc oldDesc
Definition: tablecmds.c:160
#define NoLock
Definition: lockdefs.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:1042
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:164
#define RelationGetRelationName(relation)
Definition: rel.h:511
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
Oid old_pktable_oid
Definition: parsenodes.h:2304
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2251
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:102
bool allowSystemTableMods
Definition: globals.c:123
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2309
#define ereport(elevel,...)
Definition: elog.h:157
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
Definition: tablecmds.c:10843
char fk_del_action
Definition: parsenodes.h:2302
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:11081
#define INDEX_MAX_KEYS
static int list_length(const List *l)
Definition: pg_list.h:149
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
Definition: tablecmds.c:10940
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
int i
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
RangeVar * pktable
Definition: parsenodes.h:2297
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2468
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2252
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
bool skip_validation
Definition: parsenodes.h:2308
#define RelationGetRelid(relation)
Definition: rel.h:477
List * fk_attrs
Definition: parsenodes.h:2298
#define BTEqualStrategyNumber
Definition: stratnum.h:31
char fk_upd_action
Definition: parsenodes.h:2301
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ ATCheckPartitionsNotInUse()

static void ATCheckPartitionsNotInUse ( Relation  rel,
LOCKMODE  lockmode 
)
static

Definition at line 6268 of file tablecmds.c.

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

Referenced by ATPrepCmd().

6269 {
6270  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6271  {
6272  List *inh;
6273  ListCell *cell;
6274 
6275  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6276  /* first element is the parent rel; must ignore it */
6277  for_each_from(cell, inh, 1)
6278  {
6279  Relation childrel;
6280 
6281  /* find_all_inheritors already got lock */
6282  childrel = table_open(lfirst_oid(cell), NoLock);
6283  CheckTableNotInUse(childrel, "ALTER TABLE");
6284  table_close(childrel, NoLock);
6285  }
6286  list_free(inh);
6287  }
6288 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Form_pg_class rd_rel
Definition: rel.h:109
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3943
#define for_each_from(cell, lst, N)
Definition: pg_list.h:393
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:256
void list_free(List *list)
Definition: list.c:1391
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:477
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ ATColumnChangeRequiresRewrite()

static bool ATColumnChangeRequiresRewrite ( Node expr,
AttrNumber  varattno 
)
static

Definition at line 11958 of file tablecmds.c.

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

Referenced by ATPrepAlterColumnType().

11959 {
11960  Assert(expr != NULL);
11961 
11962  for (;;)
11963  {
11964  /* only one varno, so no need to check that */
11965  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
11966  return false;
11967  else if (IsA(expr, RelabelType))
11968  expr = (Node *) ((RelabelType *) expr)->arg;
11969  else if (IsA(expr, CoerceToDomain))
11970  {
11971  CoerceToDomain *d = (CoerceToDomain *) expr;
11972 
11974  return true;
11975  expr = (Node *) d->arg;
11976  }
11977  else if (IsA(expr, FuncExpr))
11978  {
11979  FuncExpr *f = (FuncExpr *) expr;
11980 
11981  switch (f->funcid)
11982  {
11983  case F_TIMESTAMPTZ_TIMESTAMP:
11984  case F_TIMESTAMP_TIMESTAMPTZ:
11986  return true;
11987  else
11988  expr = linitial(f->args);
11989  break;
11990  default:
11991  return true;
11992  }
11993  }
11994  else
11995  return true;
11996  }
11997 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:588
List * args
Definition: primnodes.h:503
Definition: nodes.h:537
Definition: primnodes.h:186
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1392
#define linitial(l)
Definition: pg_list.h:174
Oid funcid
Definition: primnodes.h:495
#define Assert(condition)
Definition: c.h:804
void * arg
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:5487

◆ ATController()

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

Definition at line 4372 of file tablecmds.c.

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

Referenced by AlterTable(), and AlterTableInternal().

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

◆ ATDetachCheckNoForeignKeyRefs()

static void ATDetachCheckNoForeignKeyRefs ( Relation  partition)
static

Definition at line 18750 of file tablecmds.c.

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

Referenced by ATExecDetachPartition().

18751 {
18752  List *constraints;
18753  ListCell *cell;
18754 
18755  constraints = GetParentedForeignKeyRefs(partition);
18756 
18757  foreach(cell, constraints)
18758  {
18759  Oid constrOid = lfirst_oid(cell);
18760  HeapTuple tuple;
18761  Form_pg_constraint constrForm;
18762  Relation rel;
18763  Trigger trig;
18764 
18765  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
18766  if (!HeapTupleIsValid(tuple))
18767  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
18768  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
18769 
18770  Assert(OidIsValid(constrForm->conparentid));
18771  Assert(constrForm->confrelid == RelationGetRelid(partition));
18772 
18773  /* prevent data changes into the referencing table until commit */
18774  rel = table_open(constrForm->conrelid, ShareLock);
18775 
18776  MemSet(&trig, 0, sizeof(trig));
18777  trig.tgoid = InvalidOid;
18778  trig.tgname = NameStr(constrForm->conname);
18780  trig.tgisinternal = true;
18781  trig.tgconstrrelid = RelationGetRelid(partition);
18782  trig.tgconstrindid = constrForm->conindid;
18783  trig.tgconstraint = constrForm->oid;
18784  trig.tgdeferrable = false;
18785  trig.tginitdeferred = false;
18786  /* we needn't fill in remaining fields */
18787 
18788  RI_PartitionRemove_Check(&trig, rel, partition);
18789 
18790  ReleaseSysCache(tuple);
18791 
18792  table_close(rel, NoLock);
18793  }
18794 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
static List * GetParentedForeignKeyRefs(Relation partition)
Definition: tablecmds.c:18697
Oid tgoid
Definition: reltrigger.h:25
bool tgisinternal
Definition: reltrigger.h:31
#define MemSet(start, val, len)
Definition: c.h:1008
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:148
char tgenabled
Definition: reltrigger.h:30
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
Oid tgconstraint
Definition: reltrigger.h:35
char * tgname
Definition: reltrigger.h:27
void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1583
bool tgdeferrable
Definition: reltrigger.h:36
bool tginitdeferred
Definition: reltrigger.h:37
#define NoLock
Definition: lockdefs.h:34
Oid tgconstrrelid
Definition: reltrigger.h:33
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
#define InvalidOid
Definition: postgres_ext.h:36
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
Oid tgconstrindid
Definition: reltrigger.h:34
#define elog(elevel,...)
Definition: elog.h:232
#define ShareLock
Definition: lockdefs.h:41
#define NameStr(name)
Definition: c.h:681
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:477
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 16451 of file tablecmds.c.

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

16453 {
16454  ListCell *cur_item;
16455 
16456  foreach(cur_item, on_commits)
16457  {
16458  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16459 
16460  if (!isCommit && oc->creating_subid == mySubid)
16461  {
16462  /* cur_item must be removed */
16464  pfree(oc);
16465  }
16466  else
16467  {
16468  /* cur_item must be preserved */
16469  if (oc->creating_subid == mySubid)
16470  oc->creating_subid = parentSubid;
16471  if (oc->deleting_subid == mySubid)
16472  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
16473  }
16474  }
16475 }
SubTransactionId creating_subid
Definition: tablecmds.c:119
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
void pfree(void *pointer)
Definition: mcxt.c:1169
static List * on_commits
Definition: tablecmds.c:123
SubTransactionId deleting_subid
Definition: tablecmds.c:120
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:593

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 16419 of file tablecmds.c.

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

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

16420 {
16421  ListCell *cur_item;
16422 
16423  foreach(cur_item, on_commits)
16424  {
16425  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16426 
16427  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
16429  {
16430  /* cur_item must be removed */
16432  pfree(oc);
16433  }
16434  else
16435  {
16436  /* cur_item must be preserved */
16439  }
16440  }
16441 }
SubTransactionId creating_subid
Definition: tablecmds.c:119
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
void pfree(void *pointer)
Definition: mcxt.c:1169
static List * on_commits
Definition: tablecmds.c:123
SubTransactionId deleting_subid
Definition: tablecmds.c:120
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:593

◆ ATExecAddColumn()

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

Definition at line 6577 of file tablecmds.c.

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

Referenced by ATExecCmd().

6582 {
6583  Oid myrelid = RelationGetRelid(rel);
6584  ColumnDef *colDef = castNode(ColumnDef, (*cmd)->def);
6585  bool if_not_exists = (*cmd)->missing_ok;
6586  Relation pgclass,
6587  attrdesc;
6588  HeapTuple reltup;
6589  FormData_pg_attribute attribute;
6590  int newattnum;
6591  char relkind;
6592  HeapTuple typeTuple;
6593  Oid typeOid;
6594  int32 typmod;
6595  Oid collOid;
6596  Form_pg_type tform;
6597  Expr *defval;
6598  List *children;
6599  ListCell *child;
6600  AlterTableCmd *childcmd;
6601  AclResult aclresult;
6602  ObjectAddress address;
6603  TupleDesc tupdesc;
6604  FormData_pg_attribute *aattr[] = {&attribute};
6605 
6606  /* At top level, permission check was done in ATPrepCmd, else do it */
6607  if (recursing)
6608  ATSimplePermissions((*cmd)->subtype, rel, ATT_TABLE | ATT_FOREIGN_TABLE);
6609 
6610  if (rel->rd_rel->relispartition && !recursing)
6611  ereport(ERROR,
6612  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6613  errmsg("cannot add column to a partition")));
6614 
6615  attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
6616 
6617  /*
6618  * Are we adding the column to a recursion child? If so, check whether to
6619  * merge with an existing definition for the column. If we do merge, we
6620  * must not recurse. Children will already have the column, and recursing
6621  * into them would mess up attinhcount.
6622  */
6623  if (colDef->inhcount > 0)
6624  {
6625  HeapTuple tuple;
6626 
6627  /* Does child already have a column by this name? */
6628  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
6629  if (HeapTupleIsValid(tuple))
6630  {
6631  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
6632  Oid ctypeId;
6633  int32 ctypmod;
6634  Oid ccollid;
6635 
6636  /* Child column must match on type, typmod, and collation */
6637  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
6638  if (ctypeId != childatt->atttypid ||
6639  ctypmod != childatt->atttypmod)
6640  ereport(ERROR,
6641  (errcode(ERRCODE_DATATYPE_MISMATCH),
6642  errmsg("child table \"%s\" has different type for column \"%s\"",
6643  RelationGetRelationName(rel), colDef->colname)));
6644  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
6645  if (ccollid != childatt->attcollation)
6646  ereport(ERROR,
6647  (errcode(ERRCODE_COLLATION_MISMATCH),
6648  errmsg("child table \"%s\" has different collation for column \"%s\"",
6649  RelationGetRelationName(rel), colDef->colname),
6650  errdetail("\"%s\" versus \"%s\"",
6651  get_collation_name(ccollid),
6652  get_collation_name(childatt->attcollation))));
6653 
6654  /* Bump the existing child att's inhcount */
6655  childatt->attinhcount++;
6656  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
6657 
6658  heap_freetuple(tuple);
6659 
6660  /* Inform the user about the merge */
6661  ereport(NOTICE,
6662  (errmsg("merging definition of column \"%s\" for child \"%s\"",
6663  colDef->colname, RelationGetRelationName(rel))));
6664 
6665  table_close(attrdesc, RowExclusiveLock);
6666  return InvalidObjectAddress;
6667  }
6668  }
6669 
6670  /* skip if the name already exists and if_not_exists is true */
6671  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
6672  {
6673  table_close(attrdesc, RowExclusiveLock);
6674  return InvalidObjectAddress;
6675  }
6676 
6677  /*
6678  * Okay, we need to add the column, so go ahead and do parse
6679  * transformation. This can result in queueing up, or even immediately
6680  * executing, subsidiary operations (such as creation of unique indexes);
6681  * so we mustn't do it until we have made the if_not_exists check.
6682  *
6683  * When recursing, the command was already transformed and we needn't do
6684  * so again. Also, if context isn't given we can't transform. (That
6685  * currently happens only for AT_AddColumnToView; we expect that view.c
6686  * passed us a ColumnDef that doesn't need work.)
6687  */
6688  if (context != NULL && !recursing)
6689  {
6690  *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
6691  cur_pass, context);
6692  Assert(*cmd != NULL);
6693  colDef = castNode(ColumnDef, (*cmd)->def);
6694  }
6695 
6696  /*
6697  * Cannot add identity column if table has children, because identity does
6698  * not inherit. (Adding column and identity separately will work.)
6699  */
6700  if (colDef->identity &&
6701  recurse &&
6702  find_inheritance_children(myrelid, NoLock) != NIL)
6703  ereport(ERROR,
6704  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6705  errmsg("cannot recursively add identity column to table that has child tables")));
6706 
6707  pgclass = table_open(RelationRelationId, RowExclusiveLock);
6708 
6709  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
6710  if (!HeapTupleIsValid(reltup))
6711  elog(ERROR, "cache lookup failed for relation %u", myrelid);
6712  relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
6713 
6714  /* Determine the new attribute's number */
6715  newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
6716  if (newattnum > MaxHeapAttributeNumber)
6717  ereport(ERROR,
6718  (errcode(ERRCODE_TOO_MANY_COLUMNS),
6719  errmsg("tables can have at most %d columns",
6721 
6722  typeTuple = typenameType(NULL, colDef->typeName, &typmod);
6723  tform = (Form_pg_type) GETSTRUCT(typeTuple);
6724  typeOid = tform->oid;
6725 
6726  aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
6727  if (aclresult != ACLCHECK_OK)
6728  aclcheck_error_type(aclresult, typeOid);
6729 
6730  collOid = GetColumnDefCollation(NULL, colDef, typeOid);
6731 
6732  /* make sure datatype is legal for a column */
6733  CheckAttributeType(colDef->colname, typeOid, collOid,
6734  list_make1_oid(rel->rd_rel->reltype),
6735  0);
6736 
6737  /* construct new attribute's pg_attribute entry */
6738  attribute.attrelid = myrelid;
6739  namestrcpy(&(attribute.attname), colDef->colname);
6740  attribute.atttypid = typeOid;
6741  attribute.attstattarget = (newattnum > 0) ? -1 : 0;
6742  attribute.attlen = tform->typlen;
6743  attribute.attnum = newattnum;
6744  attribute.attndims = list_length(colDef->typeName->arrayBounds);
6745  attribute.atttypmod = typmod;
6746  attribute.attbyval = tform->typbyval;
6747  attribute.attalign = tform->typalign;
6748  attribute.attstorage = tform->typstorage;
6749  attribute.attcompression = GetAttributeCompression(typeOid,
6750  colDef->compression);
6751  attribute.attnotnull = colDef->is_not_null;
6752  attribute.atthasdef = false;
6753  attribute.atthasmissing = false;
6754  attribute.attidentity = colDef->identity;
6755  attribute.attgenerated = colDef->generated;
6756  attribute.attisdropped = false;
6757  attribute.attislocal = colDef->is_local;
6758  attribute.attinhcount = colDef->inhcount;
6759  attribute.attcollation = collOid;
6760 
6761  /* attribute.attacl is handled by InsertPgAttributeTuples() */
6762 
6763  ReleaseSysCache(typeTuple);
6764 
6765  tupdesc = CreateTupleDesc(lengthof(aattr), (FormData_pg_attribute **) &aattr);
6766 
6767  InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
6768 
6769  table_close(attrdesc, RowExclusiveLock);
6770 
6771  /*
6772  * Update pg_class tuple as appropriate
6773  */
6774  ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
6775 
6776  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
6777 
6778  heap_freetuple(reltup);
6779 
6780  /* Post creation hook for new attribute */
6781  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
6782 
6783  table_close(pgclass, RowExclusiveLock);
6784 
6785  /* Make the attribute's catalog entry visible */
6787 
6788  /*
6789  * Store the DEFAULT, if any, in the catalogs
6790  */
6791  if (colDef->raw_default)
6792  {
6793  RawColumnDefault *rawEnt;
6794 
6795  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
6796  rawEnt->attnum = attribute.attnum;
6797  rawEnt->raw_default = copyObject(colDef->raw_default);
6798 
6799  /*
6800  * Attempt to skip a complete table rewrite by storing the specified
6801  * DEFAULT value outside of the heap. This may be disabled inside
6802  * AddRelationNewConstraints if the optimization cannot be applied.
6803  */
6804  rawEnt->missingMode = (!colDef->generated);
6805 
6806  rawEnt->generated = colDef->generated;
6807 
6808  /*
6809  * This function is intended for CREATE TABLE, so it processes a
6810  * _list_ of defaults, but we just do one.
6811  */
6813  false, true, false, NULL);
6814 
6815  /* Make the additional catalog changes visible */
6817 
6818  /*
6819  * Did the request for a missing value work? If not we'll have to do a
6820  * rewrite
6821  */
6822  if (!rawEnt->missingMode)
6824  }
6825 
6826  /*
6827  * Tell Phase 3 to fill in the default expression, if there is one.
6828  *
6829  * If there is no default, Phase 3 doesn't have to do anything, because
6830  * that effectively means that the default is NULL. The heap tuple access
6831  * routines always check for attnum > # of attributes in tuple, and return
6832  * NULL if so, so without any modification of the tuple data we will get
6833  * the effect of NULL values in the new column.
6834  *
6835  * An exception occurs when the new column is of a domain type: the domain
6836  * might have a NOT NULL constraint, or a check constraint that indirectly
6837  * rejects nulls. If there are any domain constraints then we construct
6838  * an explicit NULL default value that will be passed through
6839  * CoerceToDomain processing. (This is a tad inefficient, since it causes
6840  * rewriting the table which we really don't have to do, but the present
6841  * design of domain processing doesn't offer any simple way of checking
6842  * the constraints more directly.)
6843  *
6844  * Note: we use build_column_default, and not just the cooked default
6845  * returned by AddRelationNewConstraints, so that the right thing happens
6846  * when a datatype's default applies.
6847  *
6848  * Note: it might seem that this should happen at the end of Phase 2, so
6849  * that the effects of subsequent subcommands can be taken into account.
6850  * It's intentional that we do it now, though. The new column should be
6851  * filled according to what is said in the ADD COLUMN subcommand, so that
6852  * the effects are the same as if this subcommand had been run by itself
6853  * and the later subcommands had been issued in new ALTER TABLE commands.
6854  *
6855  * We can skip this entirely for relations without storage, since Phase 3
6856  * is certainly not going to touch them. System attributes don't have
6857  * interesting defaults, either.
6858  */
6859  if (RELKIND_HAS_STORAGE(relkind) && attribute.attnum > 0)
6860  {
6861  /*
6862  * For an identity column, we can't use build_column_default(),
6863  * because the sequence ownership isn't set yet. So do it manually.
6864  */
6865  if (colDef->identity)
6866  {
6868 
6869  nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
6870  nve->typeId = typeOid;
6871 
6872  defval = (Expr *) nve;
6873 
6874  /* must do a rewrite for identity columns */
6876  }
6877  else
6878  defval = (Expr *) build_column_default(rel, attribute.attnum);
6879 
6880  if (!defval && DomainHasConstraints(typeOid))
6881  {
6882  Oid baseTypeId;
6883  int32 baseTypeMod;
6884  Oid baseTypeColl;
6885 
6886  baseTypeMod = typmod;
6887  baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
6888  baseTypeColl = get_typcollation(baseTypeId);
6889  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
6890  defval = (Expr *) coerce_to_target_type(NULL,
6891  (Node *) defval,
6892  baseTypeId,
6893  typeOid,
6894  typmod,
6897  -1);
6898  if (defval == NULL) /* should not happen */
6899  elog(ERROR, "failed to coerce base type to domain");
6900  }
6901 
6902  if (defval)
6903  {
6905 
6906  newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
6907  newval->attnum = attribute.attnum;
6908  newval->expr = expression_planner(defval);
6909  newval->is_generated = (colDef->generated != '\0');
6910 
6911  tab->newvals = lappend(tab->newvals, newval);
6912  }
6913 
6914  if (DomainHasConstraints(typeOid))
6916 
6917  if (!TupleDescAttr(rel->rd_att, attribute.attnum - 1)->atthasmissing)
6918  {
6919  /*
6920  * If the new column is NOT NULL, and there is no missing value,
6921  * tell Phase 3 it needs to check for NULLs.
6922  */
6923  tab->verify_new_notnull |= colDef->is_not_null;
6924  }
6925  }
6926 
6927  /*
6928  * Add needed dependency entries for the new column.
6929  */
6930  add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
6931  add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
6932 
6933  /*
6934  * Propagate to children as appropriate. Unlike most other ALTER
6935  * routines, we have to do this one level of recursion at a time; we can't
6936  * use find_all_inheritors to do it in one pass.
6937  */
6938  children =
6940 
6941  /*
6942  * If we are told not to recurse, there had better not be any child
6943  * tables; else the addition would put them out of step.
6944  */
6945  if (children && !recurse)
6946  ereport(ERROR,
6947  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6948  errmsg("column must be added to child tables too")));
6949 
6950  /* Children should see column as singly inherited */
6951  if (!recursing)
6952  {
6953  childcmd = copyObject(*cmd);
6954  colDef = castNode(ColumnDef, childcmd->def);
6955  colDef->inhcount = 1;
6956  colDef->is_local = false;
6957  }
6958  else
6959  childcmd = *cmd; /* no need to copy again */
6960 
6961  foreach(child, children)
6962  {
6963  Oid childrelid = lfirst_oid(child);
6964  Relation childrel;
6965  AlteredTableInfo *childtab;
6966 
6967  /* find_inheritance_children already got lock */
6968  childrel = table_open(childrelid, NoLock);
6969  CheckTableNotInUse(childrel, "ALTER TABLE");
6970 
6971  /* Find or create work queue entry for this table */
6972  childtab = ATGetQueueEntry(wqueue, childrel);
6973 
6974  /* Recurse to child; return value is ignored */
6975  ATExecAddColumn(wqueue, childtab, childrel,
6976  &childcmd, recurse, true,
6977  lockmode, cur_pass, context);
6978 
6979  table_close(childrel, NoLock);
6980  }
6981 
6982  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
6983  return address;
6984 }
#define NIL
Definition: pg_list.h:65
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2581
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2485
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:264
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
AttrNumber attnum
Definition: heap.h:29
bool is_local
Definition: parsenodes.h:674
Oid GetUserId(void)
Definition: miscinit.c:495
#define castNode(_type_, nodeptr)
Definition: nodes.h:606
void namestrcpy(Name name, const char *str)
Definition: name.c:233
char identity
Definition: parsenodes.h:680
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:79
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * get_collation_name(Oid colloid)
Definition: lsyscache.c:1060
Expr * expression_planner(Expr *expr)
Definition: planner.c:5807
Definition: nodes.h:537
int errcode(int sqlerrcode)
Definition: elog.c:698
static char GetAttributeCompression(Oid atttypid, char *compression)
Definition: tablecmds.c:18800
char generated
Definition: parsenodes.h:683
bool is_not_null
Definition: parsenodes.h:675
#define lengthof(array)
Definition: c.h:734
Form_pg_class rd_rel
Definition: rel.h:109
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define ATT_TABLE
Definition: tablecmds.c:306
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3621
signed int int32
Definition: c.h:429
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:337
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1392
#define list_make1(x1)
Definition: pg_list.h:206
RangeVar * identitySequence
Definition: parsenodes.h:681
static void ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets)
Definition: tablecmds.c:6151
#define AT_REWRITE_DEFAULT_VAL
Definition: event_trigger.h:33
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
Definition: tablecmds.c:7044
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:1291
ItemPointerData t_self
Definition: htup.h:65
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:7062
bool missingMode
Definition: heap.h:31
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:1042
char generated
Definition: heap.h:32
#define RelationGetRelationName(relation)
Definition: rel.h:511
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5970
Node * raw_default
Definition: heap.h:30
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
#define ACL_USAGE
Definition: parsenodes.h:90
void InsertPgAttributeTuples(Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, Datum *attoptions, CatalogIndexState indstate)
Definition: heap.c:739
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3943
bool verify_new_notnull
Definition: tablecmds.c:177
Node * raw_default
Definition: parsenodes.h:678
List * lappend(List *list, void *datum)
Definition: list.c:336
Oid GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid)
Definition: parse_type.c:542
Node * build_column_default(Relation rel, int attrno)
void * palloc0(Size size)
Definition: mcxt.c:1093
AclResult
Definition: acl.h:177
void CommandCounterIncrement(void)
Definition: xact.c:1022
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
#define list_make1_oid(x1)
Definition: pg_list.h:236
static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd **cmd, bool recurse, bool recursing, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:6577
TupleDesc rd_att
Definition: rel.h:110
void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, Oid *typeid_p, int32 *typmod_p)
Definition: parse_type.c:310
FormData_pg_attribute
Definition: pg_attribute.h:191
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:59
#define ereport(elevel,...)
Definition: elog.h:157
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3003
#define NOTICE
Definition: elog.h:37
#define MaxHeapAttributeNumber
Definition: htup_details.h:47
#define makeNode(_type_)
Definition: nodes.h:585
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
static AlterTableCmd * ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:5198
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
static int list_length(const List *l)
Definition: pg_list.h:149
bool is_generated
Definition: tablecmds.c:223
#define newval
TypeName * typeName
Definition: parsenodes.h:671
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
List * arrayBounds
Definition: parsenodes.h:227
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:6991
#define elog(elevel,...)
Definition: elog.h:232
int inhcount
Definition: parsenodes.h:673
char * colname
Definition: parsenodes.h:670
char * compression
Definition: parsenodes.h:672
#define copyObject(obj)
Definition: nodes.h:653
TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs)
Definition: tupdesc.c:90
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
Definition: heap.c:590
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4806
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:311
#define RelationGetRelid(relation)
Definition: rel.h:477
#define lfirst_oid(lc)
Definition: pg_list.h:171
AttrNumber attnum
Definition: tablecmds.c:220

◆ ATExecAddConstraint()

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

Definition at line 8699 of file tablecmds.c.

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

Referenced by ATExecCmd().

8702 {
8704 
8705  Assert(IsA(newConstraint, Constraint));
8706 
8707  /*
8708  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
8709  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
8710  * switch anyway to make it easier to add more code later.
8711  */
8712  switch (newConstraint->contype)
8713  {
8714  case CONSTR_CHECK:
8715  address =
8716  ATAddCheckConstraint(wqueue, tab, rel,
8717  newConstraint, recurse, false, is_readd,
8718  lockmode);
8719  break;
8720 
8721  case CONSTR_FOREIGN:
8722 
8723  /*
8724  * Assign or validate constraint name
8725  */
8726  if (newConstraint->conname)
8727  {
8729  RelationGetRelid(rel),
8730  newConstraint->conname))
8731  ereport(ERROR,
8733  errmsg("constraint \"%s\" for relation \"%s\" already exists",
8734  newConstraint->conname,
8735  RelationGetRelationName(rel))));
8736  }
8737  else
8738  newConstraint->conname =
8741  "fkey",
8742  RelationGetNamespace(rel),
8743  NIL);
8744 
8745  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
8746  newConstraint,
8747  recurse, false,
8748  lockmode);
8749  break;
8750 
8751  default:
8752  elog(ERROR, "unrecognized constraint type: %d",
8753  (int) newConstraint->contype);
8754  }
8755 
8756  return address;
8757 }
#define NIL
Definition: pg_list.h:65
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
#define IsA(nodeptr, _type_)
Definition: nodes.h:588
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8772
int errcode(int sqlerrcode)
Definition: elog.c:698
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:8814
char * conname
Definition: parsenodes.h:2266
#define ERROR
Definition: elog.h:46
#define RelationGetRelationName(relation)
Definition: rel.h:511
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:8951
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
ConstrType contype
Definition:<