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 truncate_update_partedrel_stats (List *parted_rels)
 
static void RangeVarCallbackForTruncate (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
static ListMergeAttributes (List *schema, List *supers, char relpersistence, bool is_partition, List **supconstr)
 
static bool MergeCheckConstraint (List *constraints, char *name, Node *expr)
 
static void MergeAttributesIntoExisting (Relation child_rel, Relation parent_rel)
 
static void MergeConstraintsIntoExisting (Relation child_rel, Relation parent_rel)
 
static void StoreCatalogInheritance (Oid relationId, List *supers, bool child_is_partition)
 
static void StoreCatalogInheritance1 (Oid relationId, Oid parentOid, int32 seqNumber, Relation inhRelation, bool child_is_partition)
 
static int findAttrByName (const char *attributeName, List *schema)
 
static void AlterIndexNamespaces (Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
 
static void AlterSeqNamespaces (Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
 
static ObjectAddress ATExecAlterConstraint (Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
 
static 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 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 7040 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

7041 {
7042  ObjectAddress myself,
7043  referenced;
7044 
7045  /* We know the default collation is pinned, so don't bother recording it */
7046  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7047  {
7048  myself.classId = RelationRelationId;
7049  myself.objectId = relid;
7050  myself.objectSubId = attnum;
7051  referenced.classId = CollationRelationId;
7052  referenced.objectId = collid;
7053  referenced.objectSubId = 0;
7054  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7055  }
7056 }
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 7022 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

7023 {
7024  ObjectAddress myself,
7025  referenced;
7026 
7027  myself.classId = RelationRelationId;
7028  myself.objectId = relid;
7029  myself.objectSubId = attnum;
7030  referenced.classId = TypeRelationId;
7031  referenced.objectId = typid;
7032  referenced.objectSubId = 0;
7033  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7034 }
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 9368 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().

9373 {
9374  ObjectAddress address;
9375  Oid constrOid;
9376  char *conname;
9377  bool conislocal;
9378  int coninhcount;
9379  bool connoinherit;
9380 
9381  /*
9382  * Verify relkind for each referenced partition. At the top level, this
9383  * is redundant with a previous check, but we need it when recursing.
9384  */
9385  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
9386  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
9387  ereport(ERROR,
9388  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9389  errmsg("referenced relation \"%s\" is not a table",
9390  RelationGetRelationName(pkrel))));
9391 
9392  /*
9393  * Caller supplies us with a constraint name; however, it may be used in
9394  * this partition, so come up with a different one in that case.
9395  */
9397  RelationGetRelid(rel),
9398  fkconstraint->conname))
9401  "fkey",
9402  RelationGetNamespace(rel), NIL);
9403  else
9404  conname = fkconstraint->conname;
9405 
9406  if (OidIsValid(parentConstr))
9407  {
9408  conislocal = false;
9409  coninhcount = 1;
9410  connoinherit = false;
9411  }
9412  else
9413  {
9414  conislocal = true;
9415  coninhcount = 0;
9416 
9417  /*
9418  * always inherit for partitioned tables, never for legacy inheritance
9419  */
9420  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
9421  }
9422 
9423  /*
9424  * Record the FK constraint in pg_constraint.
9425  */
9426  constrOid = CreateConstraintEntry(conname,
9427  RelationGetNamespace(rel),
9428  CONSTRAINT_FOREIGN,
9429  fkconstraint->deferrable,
9430  fkconstraint->initdeferred,
9431  fkconstraint->initially_valid,
9432  parentConstr,
9433  RelationGetRelid(rel),
9434  fkattnum,
9435  numfks,
9436  numfks,
9437  InvalidOid, /* not a domain constraint */
9438  indexOid,
9439  RelationGetRelid(pkrel),
9440  pkattnum,
9441  pfeqoperators,
9442  ppeqoperators,
9443  ffeqoperators,
9444  numfks,
9445  fkconstraint->fk_upd_action,
9446  fkconstraint->fk_del_action,
9447  fkconstraint->fk_matchtype,
9448  NULL, /* no exclusion constraint */
9449  NULL, /* no check constraint */
9450  NULL,
9451  conislocal, /* islocal */
9452  coninhcount, /* inhcount */
9453  connoinherit, /* conNoInherit */
9454  false); /* is_internal */
9455 
9456  ObjectAddressSet(address, ConstraintRelationId, constrOid);
9457 
9458  /*
9459  * Mark the child constraint as part of the parent constraint; it must not
9460  * be dropped on its own. (This constraint is deleted when the partition
9461  * is detached, but a special check needs to occur that the partition
9462  * contains no referenced values.)
9463  */
9464  if (OidIsValid(parentConstr))
9465  {
9466  ObjectAddress referenced;
9467 
9468  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9469  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
9470  }
9471 
9472  /* make new constraint visible, in case we add more */
9474 
9475  /*
9476  * If the referenced table is a plain relation, create the action triggers
9477  * that enforce the constraint.
9478  */
9479  if (pkrel->rd_rel->relkind == RELKIND_RELATION)
9480  {
9482  fkconstraint,
9483  constrOid, indexOid);
9484  }
9485 
9486  /*
9487  * If the referenced table is partitioned, recurse on ourselves to handle
9488  * each partition. We need one pg_constraint row created for each
9489  * partition in addition to the pg_constraint row for the parent table.
9490  */
9491  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9492  {
9493  PartitionDesc pd = RelationGetPartitionDesc(pkrel, true);
9494 
9495  for (int i = 0; i < pd->nparts; i++)
9496  {
9497  Relation partRel;
9498  AttrMap *map;
9499  AttrNumber *mapped_pkattnum;
9500  Oid partIndexId;
9501 
9502  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
9503 
9504  /*
9505  * Map the attribute numbers in the referenced side of the FK
9506  * definition to match the partition's column layout.
9507  */
9509  RelationGetDescr(pkrel));
9510  if (map)
9511  {
9512  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
9513  for (int j = 0; j < numfks; j++)
9514  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
9515  }
9516  else
9517  mapped_pkattnum = pkattnum;
9518 
9519  /* do the deed */
9520  partIndexId = index_get_partition(partRel, indexOid);
9521  if (!OidIsValid(partIndexId))
9522  elog(ERROR, "index for %u not found in partition %s",
9523  indexOid, RelationGetRelationName(partRel));
9524  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
9525  partIndexId, constrOid, numfks,
9526  mapped_pkattnum, fkattnum,
9527  pfeqoperators, ppeqoperators, ffeqoperators,
9528  old_check_ok);
9529 
9530  /* Done -- clean up (but keep the lock) */
9531  table_close(partRel, NoLock);
9532  if (map)
9533  {
9534  pfree(mapped_pkattnum);
9535  free_attrmap(map);
9536  }
9537  }
9538  }
9539 
9540  return address;
9541 }
#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:8750
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:2288
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:2256
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
char * conname
Definition: parsenodes.h:2254
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:9368
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:2255
#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:11263
void CommandCounterIncrement(void)
Definition: xact.c:1021
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2297
#define ereport(elevel,...)
Definition: elog.h:157
char fk_del_action
Definition: parsenodes.h:2290
#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:2286
char fk_upd_action
Definition: parsenodes.h:2289
#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 9573 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().

9578 {
9579  AssertArg(OidIsValid(parentConstr));
9580 
9581  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
9582  ereport(ERROR,
9583  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9584  errmsg("foreign key constraints are not supported on foreign tables")));
9585 
9586  /*
9587  * If the referencing relation is a plain table, add the check triggers to
9588  * it and, if necessary, schedule it to be checked in Phase 3.
9589  *
9590  * If the relation is partitioned, drill down to do it to its partitions.
9591  */
9592  if (rel->rd_rel->relkind == RELKIND_RELATION)
9593  {
9595  RelationGetRelid(pkrel),
9596  fkconstraint,
9597  parentConstr,
9598  indexOid);
9599 
9600  /*
9601  * Tell Phase 3 to check that the constraint is satisfied by existing
9602  * rows. We can skip this during table creation, when requested
9603  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
9604  * and when we're recreating a constraint following a SET DATA TYPE
9605  * operation that did not impugn its validity.
9606  */
9607  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
9608  {
9609  NewConstraint *newcon;
9610  AlteredTableInfo *tab;
9611 
9612  tab = ATGetQueueEntry(wqueue, rel);
9613 
9614  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9615  newcon->name = get_constraint_name(parentConstr);
9616  newcon->contype = CONSTR_FOREIGN;
9617  newcon->refrelid = RelationGetRelid(pkrel);
9618  newcon->refindid = indexOid;
9619  newcon->conid = parentConstr;
9620  newcon->qual = (Node *) fkconstraint;
9621 
9622  tab->constraints = lappend(tab->constraints, newcon);
9623  }
9624  }
9625  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9626  {
9627  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
9628 
9629  /*
9630  * Recurse to take appropriate action on each partition; either we
9631  * find an existing constraint to reparent to ours, or we create a new
9632  * one.
9633  */
9634  for (int i = 0; i < pd->nparts; i++)
9635  {
9636  Oid partitionId = pd->oids[i];
9637  Relation partition = table_open(partitionId, lockmode);
9638  List *partFKs;
9639  AttrMap *attmap;
9640  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
9641  bool attached;
9642  char *conname;
9643  Oid constrOid;
9644  ObjectAddress address,
9645  referenced;
9646  ListCell *cell;
9647 
9648  CheckTableNotInUse(partition, "ALTER TABLE");
9649 
9650  attmap = build_attrmap_by_name(RelationGetDescr(partition),
9651  RelationGetDescr(rel));
9652  for (int j = 0; j < numfks; j++)
9653  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
9654 
9655  /* Check whether an existing constraint can be repurposed */
9656  partFKs = copyObject(RelationGetFKeyList(partition));
9657  attached = false;
9658  foreach(cell, partFKs)
9659  {
9660  ForeignKeyCacheInfo *fk;
9661 
9662  fk = lfirst_node(ForeignKeyCacheInfo, cell);
9664  partitionId,
9665  parentConstr,
9666  numfks,
9667  mapped_fkattnum,
9668  pkattnum,
9669  pfeqoperators))
9670  {
9671  attached = true;
9672  break;
9673  }
9674  }
9675  if (attached)
9676  {
9677  table_close(partition, NoLock);
9678  continue;
9679  }
9680 
9681  /*
9682  * No luck finding a good constraint to reuse; create our own.
9683  */
9685  RelationGetRelid(partition),
9686  fkconstraint->conname))
9687  conname = ChooseConstraintName(RelationGetRelationName(partition),
9689  "fkey",
9690  RelationGetNamespace(partition), NIL);
9691  else
9692  conname = fkconstraint->conname;
9693  constrOid =
9694  CreateConstraintEntry(conname,
9695  RelationGetNamespace(partition),
9696  CONSTRAINT_FOREIGN,
9697  fkconstraint->deferrable,
9698  fkconstraint->initdeferred,
9699  fkconstraint->initially_valid,
9700  parentConstr,
9701  partitionId,
9702  mapped_fkattnum,
9703  numfks,
9704  numfks,
9705  InvalidOid,
9706  indexOid,
9707  RelationGetRelid(pkrel),
9708  pkattnum,
9709  pfeqoperators,
9710  ppeqoperators,
9711  ffeqoperators,
9712  numfks,
9713  fkconstraint->fk_upd_action,
9714  fkconstraint->fk_del_action,
9715  fkconstraint->fk_matchtype,
9716  NULL,
9717  NULL,
9718  NULL,
9719  false,
9720  1,
9721  false,
9722  false);
9723 
9724  /*
9725  * Give this constraint partition-type dependencies on the parent
9726  * constraint as well as the table.
9727  */
9728  ObjectAddressSet(address, ConstraintRelationId, constrOid);
9729  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9730  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
9731  ObjectAddressSet(referenced, RelationRelationId, partitionId);
9732  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
9733 
9734  /* Make all this visible before recursing */
9736 
9737  /* call ourselves to finalize the creation and we're done */
9738  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
9739  indexOid,
9740  constrOid,
9741  numfks,
9742  pkattnum,
9743  mapped_fkattnum,
9744  pfeqoperators,
9745  ppeqoperators,
9746  ffeqoperators,
9747  old_check_ok,
9748  lockmode);
9749 
9750  table_close(partition, NoLock);
9751  }
9752  }
9753 }
#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:11386
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
char * name
Definition: tablecmds.c:201
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8750
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:9573
char fk_matchtype
Definition: parsenodes.h:2288
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:50
Node * qual
Definition: tablecmds.c:206
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
bool initdeferred
Definition: parsenodes.h:2256
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
char * conname
Definition: parsenodes.h:2254
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:10170
#define ERROR
Definition: elog.h:46
bool deferrable
Definition: parsenodes.h:2255
#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:5948
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3923
#define AssertArg(condition)
Definition: c.h:806
List * lappend(List *list, void *datum)
Definition: list.c:336
ConstrType contype
Definition: tablecmds.c:202
void * palloc0(Size size)
Definition: mcxt.c:1093
void CommandCounterIncrement(void)
Definition: xact.c:1021
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2297
#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:2290
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:4464
int errmsg(const char *fmt,...)
Definition: elog.c:909
int i
#define copyObject(obj)
Definition: nodes.h:655
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
bool skip_validation
Definition: parsenodes.h:2296
#define RelationGetRelid(relation)
Definition: rel.h:477
List * fk_attrs
Definition: parsenodes.h:2286
char fk_upd_action
Definition: parsenodes.h:2289
#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 5981 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().

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

◆ AlterIndexNamespaces()

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

Definition at line 16108 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().

16110 {
16111  List *indexList;
16112  ListCell *l;
16113 
16114  indexList = RelationGetIndexList(rel);
16115 
16116  foreach(l, indexList)
16117  {
16118  Oid indexOid = lfirst_oid(l);
16119  ObjectAddress thisobj;
16120 
16121  thisobj.classId = RelationRelationId;
16122  thisobj.objectId = indexOid;
16123  thisobj.objectSubId = 0;
16124 
16125  /*
16126  * Note: currently, the index will not have its own dependency on the
16127  * namespace, so we don't need to do changeDependencyFor(). There's no
16128  * row type in pg_type, either.
16129  *
16130  * XXX this objsMoved test may be pointless -- surely we have a single
16131  * dependency link from a relation to each index?
16132  */
16133  if (!object_address_present(&thisobj, objsMoved))
16134  {
16135  AlterRelationNamespaceInternal(classRel, indexOid,
16136  oldNspOid, newNspOid,
16137  false, objsMoved);
16138  add_exact_object_address(&thisobj, objsMoved);
16139  }
16140  }
16141 
16142  list_free(indexList);
16143 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2542
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2482
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:16038
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4573
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 16038 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().

16042 {
16043  HeapTuple classTup;
16044  Form_pg_class classForm;
16045  ObjectAddress thisobj;
16046  bool already_done = false;
16047 
16048  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
16049  if (!HeapTupleIsValid(classTup))
16050  elog(ERROR, "cache lookup failed for relation %u", relOid);
16051  classForm = (Form_pg_class) GETSTRUCT(classTup);
16052 
16053  Assert(classForm->relnamespace == oldNspOid);
16054 
16055  thisobj.classId = RelationRelationId;
16056  thisobj.objectId = relOid;
16057  thisobj.objectSubId = 0;
16058 
16059  /*
16060  * If the object has already been moved, don't move it again. If it's
16061  * already in the right place, don't move it, but still fire the object
16062  * access hook.
16063  */
16064  already_done = object_address_present(&thisobj, objsMoved);
16065  if (!already_done && oldNspOid != newNspOid)
16066  {
16067  /* check for duplicate name (more friendly than unique-index failure) */
16068  if (get_relname_relid(NameStr(classForm->relname),
16069  newNspOid) != InvalidOid)
16070  ereport(ERROR,
16071  (errcode(ERRCODE_DUPLICATE_TABLE),
16072  errmsg("relation \"%s\" already exists in schema \"%s\"",
16073  NameStr(classForm->relname),
16074  get_namespace_name(newNspOid))));
16075 
16076  /* classTup is a copy, so OK to scribble on */
16077  classForm->relnamespace = newNspOid;
16078 
16079  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
16080 
16081  /* Update dependency on schema if caller said so */
16082  if (hasDependEntry &&
16083  changeDependencyFor(RelationRelationId,
16084  relOid,
16085  NamespaceRelationId,
16086  oldNspOid,
16087  newNspOid) != 1)
16088  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
16089  NameStr(classForm->relname));
16090  }
16091  if (!already_done)
16092  {
16093  add_exact_object_address(&thisobj, objsMoved);
16094 
16095  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
16096  }
16097 
16098  heap_freetuple(classTup);
16099 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2542
int errcode(int sqlerrcode)
Definition: elog.c:698
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2482
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:392
#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 16153 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().

16156 {
16157  Relation depRel;
16158  SysScanDesc scan;
16159  ScanKeyData key[2];
16160  HeapTuple tup;
16161 
16162  /*
16163  * SERIAL sequences are those having an auto dependency on one of the
16164  * table's columns (we don't care *which* column, exactly).
16165  */
16166  depRel = table_open(DependRelationId, AccessShareLock);
16167 
16168  ScanKeyInit(&key[0],
16169  Anum_pg_depend_refclassid,
16170  BTEqualStrategyNumber, F_OIDEQ,
16171  ObjectIdGetDatum(RelationRelationId));
16172  ScanKeyInit(&key[1],
16173  Anum_pg_depend_refobjid,
16174  BTEqualStrategyNumber, F_OIDEQ,
16176  /* we leave refobjsubid unspecified */
16177 
16178  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
16179  NULL, 2, key);
16180 
16181  while (HeapTupleIsValid(tup = systable_getnext(scan)))
16182  {
16183  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
16184  Relation seqRel;
16185 
16186  /* skip dependencies other than auto dependencies on columns */
16187  if (depForm->refobjsubid == 0 ||
16188  depForm->classid != RelationRelationId ||
16189  depForm->objsubid != 0 ||
16190  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
16191  continue;
16192 
16193  /* Use relation_open just in case it's an index */
16194  seqRel = relation_open(depForm->objid, lockmode);
16195 
16196  /* skip non-sequence relations */
16197  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
16198  {
16199  /* No need to keep the lock */
16200  relation_close(seqRel, lockmode);
16201  continue;
16202  }
16203 
16204  /* Fix the pg_class and pg_depend entries */
16205  AlterRelationNamespaceInternal(classRel, depForm->objid,
16206  oldNspOid, newNspOid,
16207  true, objsMoved);
16208 
16209  /*
16210  * Sequences used to have entries in pg_type, but no longer do. If we
16211  * ever re-instate that, we'll need to move the pg_type entry to the
16212  * new namespace, too (using AlterTypeNamespaceInternal).
16213  */
16214  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
16215 
16216  /* Now we can close it. Keep the lock till end of transaction. */
16217  relation_close(seqRel, NoLock);
16218  }
16219 
16220  systable_endscan(scan);
16221 
16223 }
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:16038
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 4007 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

4009 {
4010  Relation rel;
4011 
4012  /* Caller is required to provide an adequate lock. */
4013  rel = relation_open(context->relid, NoLock);
4014 
4015  CheckTableNotInUse(rel, "ALTER TABLE");
4016 
4017  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4018 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4352
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:3923
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1859

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4081 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().

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

◆ AlterTableInternal()

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

Definition at line 4036 of file tablecmds.c.

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

4037 {
4038  Relation rel;
4039  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4040 
4041  rel = relation_open(relid, lockmode);
4042 
4044 
4045  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4046 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4352
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4081
void EventTriggerAlterTableRelid(Oid objectId)

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3951 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3952 {
3953  return RangeVarGetRelidExtended(stmt->relation, lockmode,
3954  stmt->missing_ok ? RVR_MISSING_OK : 0,
3956  (void *) stmt);
3957 }
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:16552
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:237
RangeVar * relation
Definition: parsenodes.h:1859

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 14043 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().

14044 {
14045  List *relations = NIL;
14046  ListCell *l;
14047  ScanKeyData key[1];
14048  Relation rel;
14049  TableScanDesc scan;
14050  HeapTuple tuple;
14051  Oid orig_tablespaceoid;
14052  Oid new_tablespaceoid;
14053  List *role_oids = roleSpecsToIds(stmt->roles);
14054 
14055  /* Ensure we were not asked to move something we can't */
14056  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
14057  stmt->objtype != OBJECT_MATVIEW)
14058  ereport(ERROR,
14059  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14060  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
14061 
14062  /* Get the orig and new tablespace OIDs */
14063  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
14064  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
14065 
14066  /* Can't move shared relations in to or out of pg_global */
14067  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
14068  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
14069  new_tablespaceoid == GLOBALTABLESPACE_OID)
14070  ereport(ERROR,
14071  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
14072  errmsg("cannot move relations in to or out of pg_global tablespace")));
14073 
14074  /*
14075  * Must have CREATE rights on the new tablespace, unless it is the
14076  * database default tablespace (which all users implicitly have CREATE
14077  * rights on).
14078  */
14079  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
14080  {
14081  AclResult aclresult;
14082 
14083  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
14084  ACL_CREATE);
14085  if (aclresult != ACLCHECK_OK)
14086  aclcheck_error(aclresult, OBJECT_TABLESPACE,
14087  get_tablespace_name(new_tablespaceoid));
14088  }
14089 
14090  /*
14091  * Now that the checks are done, check if we should set either to
14092  * InvalidOid because it is our database's default tablespace.
14093  */
14094  if (orig_tablespaceoid == MyDatabaseTableSpace)
14095  orig_tablespaceoid = InvalidOid;
14096 
14097  if (new_tablespaceoid == MyDatabaseTableSpace)
14098  new_tablespaceoid = InvalidOid;
14099 
14100  /* no-op */
14101  if (orig_tablespaceoid == new_tablespaceoid)
14102  return new_tablespaceoid;
14103 
14104  /*
14105  * Walk the list of objects in the tablespace and move them. This will
14106  * only find objects in our database, of course.
14107  */
14108  ScanKeyInit(&key[0],
14109  Anum_pg_class_reltablespace,
14110  BTEqualStrategyNumber, F_OIDEQ,
14111  ObjectIdGetDatum(orig_tablespaceoid));
14112 
14113  rel = table_open(RelationRelationId, AccessShareLock);
14114  scan = table_beginscan_catalog(rel, 1, key);
14115  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
14116  {
14117  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
14118  Oid relOid = relForm->oid;
14119 
14120  /*
14121  * Do not move objects in pg_catalog as part of this, if an admin
14122  * really wishes to do so, they can issue the individual ALTER
14123  * commands directly.
14124  *
14125  * Also, explicitly avoid any shared tables, temp tables, or TOAST
14126  * (TOAST will be moved with the main table).
14127  */
14128  if (IsCatalogNamespace(relForm->relnamespace) ||
14129  relForm->relisshared ||
14130  isAnyTempNamespace(relForm->relnamespace) ||
14131  IsToastNamespace(relForm->relnamespace))
14132  continue;
14133 
14134  /* Only move the object type requested */
14135  if ((stmt->objtype == OBJECT_TABLE &&
14136  relForm->relkind != RELKIND_RELATION &&
14137  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
14138  (stmt->objtype == OBJECT_INDEX &&
14139  relForm->relkind != RELKIND_INDEX &&
14140  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
14141  (stmt->objtype == OBJECT_MATVIEW &&
14142  relForm->relkind != RELKIND_MATVIEW))
14143  continue;
14144 
14145  /* Check if we are only moving objects owned by certain roles */
14146  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
14147  continue;
14148 
14149  /*
14150  * Handle permissions-checking here since we are locking the tables
14151  * and also to avoid doing a bunch of work only to fail part-way. Note
14152  * that permissions will also be checked by AlterTableInternal().
14153  *
14154  * Caller must be considered an owner on the table to move it.
14155  */
14156  if (!pg_class_ownercheck(relOid, GetUserId()))
14158  NameStr(relForm->relname));
14159 
14160  if (stmt->nowait &&
14162  ereport(ERROR,
14163  (errcode(ERRCODE_OBJECT_IN_USE),
14164  errmsg("aborting because lock on relation \"%s.%s\" is not available",
14165  get_namespace_name(relForm->relnamespace),
14166  NameStr(relForm->relname))));
14167  else
14169 
14170  /* Add to our list of objects to move */
14171  relations = lappend_oid(relations, relOid);
14172  }
14173 
14174  table_endscan(scan);
14176 
14177  if (relations == NIL)
14178  ereport(NOTICE,
14179  (errcode(ERRCODE_NO_DATA_FOUND),
14180  errmsg("no matching relations in tablespace \"%s\" found",
14181  orig_tablespaceoid == InvalidOid ? "(database default)" :
14182  get_tablespace_name(orig_tablespaceoid))));
14183 
14184  /* Everything is locked, loop through and move all of the relations. */
14185  foreach(l, relations)
14186  {
14187  List *cmds = NIL;
14189 
14190  cmd->subtype = AT_SetTableSpace;
14191  cmd->name = stmt->new_tablespacename;
14192 
14193  cmds = lappend(cmds, cmd);
14194 
14196  /* OID is set by AlterTableInternal */
14197  AlterTableInternal(lfirst_oid(l), cmds, false);
14199  }
14200 
14201  return new_tablespaceoid;
14202 }
#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:1431
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:478
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1974
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:539
int errcode(int sqlerrcode)
Definition: elog.c:698
AlterTableType subtype
Definition: parsenodes.h:1950
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c: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:587
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:4036
#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:1477
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 15928 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().

15929 {
15930  Relation rel;
15931  Oid relid;
15932  Oid oldNspOid;
15933  Oid nspOid;
15934  RangeVar *newrv;
15935  ObjectAddresses *objsMoved;
15936  ObjectAddress myself;
15937 
15939  stmt->missing_ok ? RVR_MISSING_OK : 0,
15941  (void *) stmt);
15942 
15943  if (!OidIsValid(relid))
15944  {
15945  ereport(NOTICE,
15946  (errmsg("relation \"%s\" does not exist, skipping",
15947  stmt->relation->relname)));
15948  return InvalidObjectAddress;
15949  }
15950 
15951  rel = relation_open(relid, NoLock);
15952 
15953  oldNspOid = RelationGetNamespace(rel);
15954 
15955  /* If it's an owned sequence, disallow moving it by itself. */
15956  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
15957  {
15958  Oid tableId;
15959  int32 colId;
15960 
15961  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
15962  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
15963  ereport(ERROR,
15964  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15965  errmsg("cannot move an owned sequence into another schema"),
15966  errdetail("Sequence \"%s\" is linked to table \"%s\".",
15968  get_rel_name(tableId))));
15969  }
15970 
15971  /* Get and lock schema OID and check its permissions. */
15972  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
15973  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
15974 
15975  /* common checks on switching namespaces */
15976  CheckSetNamespace(oldNspOid, nspOid);
15977 
15978  objsMoved = new_object_addresses();
15979  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
15980  free_object_addresses(objsMoved);
15981 
15982  ObjectAddressSet(myself, RelationRelationId, relid);
15983 
15984  if (oldschema)
15985  *oldschema = oldNspOid;
15986 
15987  /* close rel, but keep lock until commit */
15988  relation_close(rel, NoLock);
15989 
15990  return myself;
15991 }
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:763
int errcode(int sqlerrcode)
Definition: elog.c:698
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2427
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2722
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:15999
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:16552
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 15999 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().

16001 {
16002  Relation classRel;
16003 
16004  Assert(objsMoved != NULL);
16005 
16006  /* OK, modify the pg_class row and pg_depend entry */
16007  classRel = table_open(RelationRelationId, RowExclusiveLock);
16008 
16009  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
16010  nspOid, true, objsMoved);
16011 
16012  /* Fix the table's row type too, if it has one */
16013  if (OidIsValid(rel->rd_rel->reltype))
16014  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
16015  nspOid, false, false, objsMoved);
16016 
16017  /* Fix other dependent stuff */
16018  if (rel->rd_rel->relkind == RELKIND_RELATION ||
16019  rel->rd_rel->relkind == RELKIND_MATVIEW ||
16020  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16021  {
16022  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
16023  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
16024  objsMoved, AccessExclusiveLock);
16025  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
16026  false, objsMoved);
16027  }
16028 
16029  table_close(classRel, RowExclusiveLock);
16030 }
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:16108
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:16153
#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:16038
#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 8792 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().

8795 {
8796  List *newcons;
8797  ListCell *lcon;
8798  List *children;
8799  ListCell *child;
8801 
8802  /* At top level, permission check was done in ATPrepCmd, else do it */
8803  if (recursing)
8805 
8806  /*
8807  * Call AddRelationNewConstraints to do the work, making sure it works on
8808  * a copy of the Constraint so transformExpr can't modify the original. It
8809  * returns a list of cooked constraints.
8810  *
8811  * If the constraint ends up getting merged with a pre-existing one, it's
8812  * omitted from the returned list, which is what we want: we do not need
8813  * to do any validation work. That can only happen at child tables,
8814  * though, since we disallow merging at the top level.
8815  */
8816  newcons = AddRelationNewConstraints(rel, NIL,
8817  list_make1(copyObject(constr)),
8818  recursing | is_readd, /* allow_merge */
8819  !recursing, /* is_local */
8820  is_readd, /* is_internal */
8821  NULL); /* queryString not available
8822  * here */
8823 
8824  /* we don't expect more than one constraint here */
8825  Assert(list_length(newcons) <= 1);
8826 
8827  /* Add each to-be-validated constraint to Phase 3's queue */
8828  foreach(lcon, newcons)
8829  {
8830  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
8831 
8832  if (!ccon->skip_validation)
8833  {
8834  NewConstraint *newcon;
8835 
8836  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
8837  newcon->name = ccon->name;
8838  newcon->contype = ccon->contype;
8839  newcon->qual = ccon->expr;
8840 
8841  tab->constraints = lappend(tab->constraints, newcon);
8842  }
8843 
8844  /* Save the actually assigned name if it was defaulted */
8845  if (constr->conname == NULL)
8846  constr->conname = ccon->name;
8847 
8848  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
8849  }
8850 
8851  /* At this point we must have a locked-down name to use */
8852  Assert(constr->conname != NULL);
8853 
8854  /* Advance command counter in case same table is visited multiple times */
8856 
8857  /*
8858  * If the constraint got merged with an existing constraint, we're done.
8859  * We mustn't recurse to child tables in this case, because they've
8860  * already got the constraint, and visiting them again would lead to an
8861  * incorrect value for coninhcount.
8862  */
8863  if (newcons == NIL)
8864  return address;
8865 
8866  /*
8867  * If adding a NO INHERIT constraint, no need to find our children.
8868  */
8869  if (constr->is_no_inherit)
8870  return address;
8871 
8872  /*
8873  * Propagate to children as appropriate. Unlike most other ALTER
8874  * routines, we have to do this one level of recursion at a time; we can't
8875  * use find_all_inheritors to do it in one pass.
8876  */
8877  children =
8879 
8880  /*
8881  * Check if ONLY was specified with ALTER TABLE. If so, allow the
8882  * constraint creation only if there are no children currently. Error out
8883  * otherwise.
8884  */
8885  if (!recurse && children != NIL)
8886  ereport(ERROR,
8887  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8888  errmsg("constraint must be added to child tables too")));
8889 
8890  foreach(child, children)
8891  {
8892  Oid childrelid = lfirst_oid(child);
8893  Relation childrel;
8894  AlteredTableInfo *childtab;
8895 
8896  /* find_inheritance_children already got lock */
8897  childrel = table_open(childrelid, NoLock);
8898  CheckTableNotInUse(childrel, "ALTER TABLE");
8899 
8900  /* Find or create work queue entry for this table */
8901  childtab = ATGetQueueEntry(wqueue, childrel);
8902 
8903  /* Recurse to child */
8904  ATAddCheckConstraint(wqueue, childtab, childrel,
8905  constr, recurse, true, is_readd, lockmode);
8906 
8907  table_close(childrel, NoLock);
8908  }
8909 
8910  return address;
8911 }
#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:8792
char * conname
Definition: parsenodes.h:2254
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:6129
#define ERROR
Definition: elog.h:46
#define NoLock
Definition: lockdefs.h:34
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5948
bool skip_validation
Definition: heap.h:42
ConstrType contype
Definition: heap.h:37
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3923
List * lappend(List *list, void *datum)
Definition: list.c:336
ConstrType contype
Definition: tablecmds.c:202
void * palloc0(Size size)
Definition: mcxt.c:1093
void CommandCounterIncrement(void)
Definition: xact.c:1021
bool is_no_inherit
Definition: parsenodes.h:2260
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:655
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:311
char * name
Definition: heap.h:39
#define RelationGetRelid(relation)
Definition: rel.h: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 8929 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().

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

◆ ATCheckPartitionsNotInUse()

static void ATCheckPartitionsNotInUse ( Relation  rel,
LOCKMODE  lockmode 
)
static

Definition at line 6246 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().

6247 {
6248  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6249  {
6250  List *inh;
6251  ListCell *cell;
6252 
6253  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6254  /* first element is the parent rel; must ignore it */
6255  for_each_from(cell, inh, 1)
6256  {
6257  Relation childrel;
6258 
6259  /* find_all_inheritors already got lock */
6260  childrel = table_open(lfirst_oid(cell), NoLock);
6261  CheckTableNotInUse(childrel, "ALTER TABLE");
6262  table_close(childrel, NoLock);
6263  }
6264  list_free(inh);
6265  }
6266 }
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:3923
#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 11936 of file tablecmds.c.

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

Referenced by ATPrepAlterColumnType().

11937 {
11938  Assert(expr != NULL);
11939 
11940  for (;;)
11941  {
11942  /* only one varno, so no need to check that */
11943  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
11944  return false;
11945  else if (IsA(expr, RelabelType))
11946  expr = (Node *) ((RelabelType *) expr)->arg;
11947  else if (IsA(expr, CoerceToDomain))
11948  {
11949  CoerceToDomain *d = (CoerceToDomain *) expr;
11950 
11952  return true;
11953  expr = (Node *) d->arg;
11954  }
11955  else if (IsA(expr, FuncExpr))
11956  {
11957  FuncExpr *f = (FuncExpr *) expr;
11958 
11959  switch (f->funcid)
11960  {
11961  case F_TIMESTAMPTZ_TIMESTAMP:
11962  case F_TIMESTAMP_TIMESTAMPTZ:
11964  return true;
11965  else
11966  expr = linitial(f->args);
11967  break;
11968  default:
11969  return true;
11970  }
11971  }
11972  else
11973  return true;
11974  }
11975 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
List * args
Definition: primnodes.h:503
Definition: nodes.h:539
Definition: primnodes.h:186
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c: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:5490

◆ ATController()

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

Definition at line 4352 of file tablecmds.c.

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

Referenced by AlterTable(), and AlterTableInternal().

4355 {
4356  List *wqueue = NIL;
4357  ListCell *lcmd;
4358 
4359  /* Phase 1: preliminary examination of commands, create work queue */
4360  foreach(lcmd, cmds)
4361  {
4362  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4363 
4364  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4365  }
4366 
4367  /* Close the relation, but keep lock until commit */
4368  relation_close(rel, NoLock);
4369 
4370  /* Phase 2: update system catalogs */
4371  ATRewriteCatalogs(&wqueue, lockmode, context);
4372 
4373  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4374  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4375 }
#define NIL
Definition: pg_list.h:65
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5313
#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:4387
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:4760
Definition: pg_list.h:50

◆ ATDetachCheckNoForeignKeyRefs()

static void ATDetachCheckNoForeignKeyRefs ( Relation  partition)
static

Definition at line 18693 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().

18694 {
18695  List *constraints;
18696  ListCell *cell;
18697 
18698  constraints = GetParentedForeignKeyRefs(partition);
18699 
18700  foreach(cell, constraints)
18701  {
18702  Oid constrOid = lfirst_oid(cell);
18703  HeapTuple tuple;
18704  Form_pg_constraint constrForm;
18705  Relation rel;
18706  Trigger trig;
18707 
18708  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
18709  if (!HeapTupleIsValid(tuple))
18710  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
18711  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
18712 
18713  Assert(OidIsValid(constrForm->conparentid));
18714  Assert(constrForm->confrelid == RelationGetRelid(partition));
18715 
18716  /* prevent data changes into the referencing table until commit */
18717  rel = table_open(constrForm->conrelid, ShareLock);
18718 
18719  MemSet(&trig, 0, sizeof(trig));
18720  trig.tgoid = InvalidOid;
18721  trig.tgname = NameStr(constrForm->conname);
18723  trig.tgisinternal = true;
18724  trig.tgconstrrelid = RelationGetRelid(partition);
18725  trig.tgconstrindid = constrForm->conindid;
18726  trig.tgconstraint = constrForm->oid;
18727  trig.tgdeferrable = false;
18728  trig.tginitdeferred = false;
18729  /* we needn't fill in remaining fields */
18730 
18731  RI_PartitionRemove_Check(&trig, rel, partition);
18732 
18733  ReleaseSysCache(tuple);
18734 
18735  table_close(rel, NoLock);
18736  }
18737 }
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:18640
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 16429 of file tablecmds.c.

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

16431 {
16432  ListCell *cur_item;
16433 
16434  foreach(cur_item, on_commits)
16435  {
16436  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16437 
16438  if (!isCommit && oc->creating_subid == mySubid)
16439  {
16440  /* cur_item must be removed */
16442  pfree(oc);
16443  }
16444  else
16445  {
16446  /* cur_item must be preserved */
16447  if (oc->creating_subid == mySubid)
16448  oc->creating_subid = parentSubid;
16449  if (oc->deleting_subid == mySubid)
16450  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
16451  }
16452  }
16453 }
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 16397 of file tablecmds.c.

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

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

16398 {
16399  ListCell *cur_item;
16400 
16401  foreach(cur_item, on_commits)
16402  {
16403  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16404 
16405  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
16407  {
16408  /* cur_item must be removed */
16410  pfree(oc);
16411  }
16412  else
16413  {
16414  /* cur_item must be preserved */
16417  }
16418  }
16419 }
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 6555 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().

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

8680 {
8682 
8683  Assert(IsA(newConstraint, Constraint));
8684 
8685  /*
8686  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
8687  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
8688  * switch anyway to make it easier to add more code later.
8689  */
8690  switch (newConstraint->contype)
8691  {
8692  case CONSTR_CHECK:
8693  address =
8694  ATAddCheckConstraint(wqueue, tab, rel,
8695  newConstraint, recurse, false, is_readd,
8696  lockmode);
8697  break;
8698 
8699  case CONSTR_FOREIGN:
8700 
8701  /*
8702  * Assign or validate constraint name
8703  */
8704  if (newConstraint->conname)
8705  {
8707  RelationGetRelid(rel),
8708  newConstraint->conname))
8709  ereport(ERROR,
8711  errmsg("constraint \"%s\" for relation \"%s\" already exists",
8712  newConstraint->conname,
8713  RelationGetRelationName(rel))));
8714  }
8715  else
8716  newConstraint->conname =
8719  "fkey",
8720  RelationGetNamespace(rel),
8721  NIL);
8722 
8723  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
8724  newConstraint,
8725  recurse, false,
8726  lockmode);
8727  break;
8728 
8729  default:
8730  elog(ERROR, "unrecognized constraint type: %d",
8731  (int) newConstraint->contype);
8732  }
8733 
8734  return address;
8735 }
#define NIL
Definition: pg_list.h:65
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8750
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:8792
char * conname
Definition: parsenodes.h:2254
#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:8929
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
ConstrType contype
Definition: parsenodes.h:2251
<