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

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Functions

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

Variables

static Liston_commits = NIL
 
static const struct dropmsgstrings dropmsgstringarray []
 

Macro Definition Documentation

◆ AT_NUM_PASSES

#define AT_NUM_PASSES   11

Definition at line 156 of file tablecmds.c.

◆ AT_PASS_ADD_COL

#define AT_PASS_ADD_COL   4 /* ADD COLUMN */

Definition at line 149 of file tablecmds.c.

◆ AT_PASS_ADD_CONSTR

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

Definition at line 150 of file tablecmds.c.

◆ AT_PASS_ADD_INDEX

#define AT_PASS_ADD_INDEX   8 /* ADD indexes */

Definition at line 153 of file tablecmds.c.

◆ AT_PASS_ADD_INDEXCONSTR

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

Definition at line 152 of file tablecmds.c.

◆ AT_PASS_ADD_OTHERCONSTR

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

Definition at line 154 of file tablecmds.c.

◆ AT_PASS_ALTER_TYPE

#define AT_PASS_ALTER_TYPE   1 /* ALTER COLUMN TYPE */

Definition at line 145 of file tablecmds.c.

◆ AT_PASS_COL_ATTRS

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

Definition at line 151 of file tablecmds.c.

◆ AT_PASS_DROP

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

Definition at line 144 of file tablecmds.c.

◆ AT_PASS_MISC

#define AT_PASS_MISC   10 /* other stuff */

Definition at line 155 of file tablecmds.c.

◆ AT_PASS_OLD_CONSTR

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

Definition at line 147 of file tablecmds.c.

◆ AT_PASS_OLD_INDEX

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

Definition at line 146 of file tablecmds.c.

◆ AT_PASS_UNSET

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

Definition at line 143 of file tablecmds.c.

◆ ATT_COMPOSITE_TYPE

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 319 of file tablecmds.c.

◆ ATT_FOREIGN_TABLE

#define ATT_FOREIGN_TABLE   0x0020

Definition at line 320 of file tablecmds.c.

◆ ATT_INDEX

#define ATT_INDEX   0x0008

Definition at line 318 of file tablecmds.c.

◆ ATT_MATVIEW

#define ATT_MATVIEW   0x0004

Definition at line 317 of file tablecmds.c.

◆ ATT_PARTITIONED_INDEX

#define ATT_PARTITIONED_INDEX   0x0040

Definition at line 321 of file tablecmds.c.

◆ ATT_SEQUENCE

#define ATT_SEQUENCE   0x0080

Definition at line 322 of file tablecmds.c.

◆ ATT_TABLE

#define ATT_TABLE   0x0001

Definition at line 315 of file tablecmds.c.

◆ ATT_VIEW

#define ATT_VIEW   0x0002

Definition at line 316 of file tablecmds.c.

◆ child_dependency_type

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

Definition at line 343 of file tablecmds.c.

Typedef Documentation

◆ AlteredTableInfo

◆ ForeignTruncateInfo

◆ NewColumnValue

◆ NewConstraint

typedef struct NewConstraint NewConstraint

◆ OnCommitItem

typedef struct OnCommitItem OnCommitItem

Function Documentation

◆ add_column_collation_dependency()

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

Definition at line 7200 of file tablecmds.c.

7201 {
7202  ObjectAddress myself,
7203  referenced;
7204 
7205  /* We know the default collation is pinned, so don't bother recording it */
7206  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
7207  {
7208  myself.classId = RelationRelationId;
7209  myself.objectId = relid;
7210  myself.objectSubId = attnum;
7211  referenced.classId = CollationRelationId;
7212  referenced.objectId = collid;
7213  referenced.objectSubId = 0;
7214  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7215  }
7216 }
#define OidIsValid(objectId)
Definition: c.h:759
Oid collid
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int16 attnum
Definition: pg_attribute.h:83
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

◆ add_column_datatype_dependency()

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

Definition at line 7182 of file tablecmds.c.

7183 {
7184  ObjectAddress myself,
7185  referenced;
7186 
7187  myself.classId = RelationRelationId;
7188  myself.objectId = relid;
7189  myself.objectSubId = attnum;
7190  referenced.classId = TypeRelationId;
7191  referenced.objectId = typid;
7192  referenced.objectSubId = 0;
7193  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
7194 }

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

◆ addFkRecurseReferenced()

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

Definition at line 9531 of file tablecmds.c.

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

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

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferenced().

◆ addFkRecurseReferencing()

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

Definition at line 9751 of file tablecmds.c.

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

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

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferencing().

◆ alter_table_type_to_string()

static const char* alter_table_type_to_string ( AlterTableType  cmdtype)
static

Definition at line 6139 of file tablecmds.c.

6140 {
6141  switch (cmdtype)
6142  {
6143  case AT_AddColumn:
6144  case AT_AddColumnToView:
6145  return "ADD COLUMN";
6146  case AT_ColumnDefault:
6148  return "ALTER COLUMN ... SET DEFAULT";
6149  case AT_DropNotNull:
6150  return "ALTER COLUMN ... DROP NOT NULL";
6151  case AT_SetNotNull:
6152  return "ALTER COLUMN ... SET NOT NULL";
6153  case AT_DropExpression:
6154  return "ALTER COLUMN ... DROP EXPRESSION";
6155  case AT_CheckNotNull:
6156  return NULL; /* not real grammar */
6157  case AT_SetStatistics:
6158  return "ALTER COLUMN ... SET STATISTICS";
6159  case AT_SetOptions:
6160  return "ALTER COLUMN ... SET";
6161  case AT_ResetOptions:
6162  return "ALTER COLUMN ... RESET";
6163  case AT_SetStorage:
6164  return "ALTER COLUMN ... SET STORAGE";
6165  case AT_SetCompression:
6166  return "ALTER COLUMN ... SET COMPRESSION";
6167  case AT_DropColumn:
6168  return "DROP COLUMN";
6169  case AT_AddIndex:
6170  case AT_ReAddIndex:
6171  return NULL; /* not real grammar */
6172  case AT_AddConstraint:
6173  case AT_ReAddConstraint:
6175  case AT_AddIndexConstraint:
6176  return "ADD CONSTRAINT";
6177  case AT_AlterConstraint:
6178  return "ALTER CONSTRAINT";
6179  case AT_ValidateConstraint:
6180  return "VALIDATE CONSTRAINT";
6181  case AT_DropConstraint:
6182  return "DROP CONSTRAINT";
6183  case AT_ReAddComment:
6184  return NULL; /* not real grammar */
6185  case AT_AlterColumnType:
6186  return "ALTER COLUMN ... SET DATA TYPE";
6188  return "ALTER COLUMN ... OPTIONS";
6189  case AT_ChangeOwner:
6190  return "OWNER TO";
6191  case AT_ClusterOn:
6192  return "CLUSTER ON";
6193  case AT_DropCluster:
6194  return "SET WITHOUT CLUSTER";
6195  case AT_SetAccessMethod:
6196  return "SET ACCESS METHOD";
6197  case AT_SetLogged:
6198  return "SET LOGGED";
6199  case AT_SetUnLogged:
6200  return "SET UNLOGGED";
6201  case AT_DropOids:
6202  return "SET WITHOUT OIDS";
6203  case AT_SetTableSpace:
6204  return "SET TABLESPACE";
6205  case AT_SetRelOptions:
6206  return "SET";
6207  case AT_ResetRelOptions:
6208  return "RESET";
6209  case AT_ReplaceRelOptions:
6210  return NULL; /* not real grammar */
6211  case AT_EnableTrig:
6212  return "ENABLE TRIGGER";
6213  case AT_EnableAlwaysTrig:
6214  return "ENABLE ALWAYS TRIGGER";
6215  case AT_EnableReplicaTrig:
6216  return "ENABLE REPLICA TRIGGER";
6217  case AT_DisableTrig:
6218  return "DISABLE TRIGGER";
6219  case AT_EnableTrigAll:
6220  return "ENABLE TRIGGER ALL";
6221  case AT_DisableTrigAll:
6222  return "DISABLE TRIGGER ALL";
6223  case AT_EnableTrigUser:
6224  return "ENABLE TRIGGER USER";
6225  case AT_DisableTrigUser:
6226  return "DISABLE TRIGGER USER";
6227  case AT_EnableRule:
6228  return "ENABLE RULE";
6229  case AT_EnableAlwaysRule:
6230  return "ENABLE ALWAYS RULE";
6231  case AT_EnableReplicaRule:
6232  return "ENABLE REPLICA RULE";
6233  case AT_DisableRule:
6234  return "DISABLE RULE";
6235  case AT_AddInherit:
6236  return "INHERIT";
6237  case AT_DropInherit:
6238  return "NO INHERIT";
6239  case AT_AddOf:
6240  return "OF";
6241  case AT_DropOf:
6242  return "NOT OF";
6243  case AT_ReplicaIdentity:
6244  return "REPLICA IDENTITY";
6245  case AT_EnableRowSecurity:
6246  return "ENABLE ROW SECURITY";
6247  case AT_DisableRowSecurity:
6248  return "DISABLE ROW SECURITY";
6249  case AT_ForceRowSecurity:
6250  return "FORCE ROW SECURITY";
6251  case AT_NoForceRowSecurity:
6252  return "NO FORCE ROW SECURITY";
6253  case AT_GenericOptions:
6254  return "OPTIONS";
6255  case AT_AttachPartition:
6256  return "ATTACH PARTITION";
6257  case AT_DetachPartition:
6258  return "DETACH PARTITION";
6260  return "DETACH PARTITION ... FINALIZE";
6261  case AT_AddIdentity:
6262  return "ALTER COLUMN ... ADD IDENTITY";
6263  case AT_SetIdentity:
6264  return "ALTER COLUMN ... SET";
6265  case AT_DropIdentity:
6266  return "ALTER COLUMN ... DROP IDENTITY";
6267  case AT_ReAddStatistics:
6268  return NULL; /* not real grammar */
6269  }
6270 
6271  return NULL;
6272 }
@ AT_AddIndexConstraint
Definition: parsenodes.h:2088
@ AT_DropOf
Definition: parsenodes.h:2119
@ AT_CheckNotNull
Definition: parsenodes.h:2074
@ AT_SetOptions
Definition: parsenodes.h:2076
@ AT_DropIdentity
Definition: parsenodes.h:2131
@ AT_DisableTrigUser
Definition: parsenodes.h:2111
@ AT_DropNotNull
Definition: parsenodes.h:2071
@ AT_AddOf
Definition: parsenodes.h:2118
@ AT_ResetOptions
Definition: parsenodes.h:2077
@ AT_ReplicaIdentity
Definition: parsenodes.h:2120
@ AT_ReplaceRelOptions
Definition: parsenodes.h:2103
@ AT_EnableRowSecurity
Definition: parsenodes.h:2121
@ AT_AddColumnToView
Definition: parsenodes.h:2068
@ AT_ResetRelOptions
Definition: parsenodes.h:2102
@ AT_EnableReplicaTrig
Definition: parsenodes.h:2106
@ AT_DropOids
Definition: parsenodes.h:2098
@ AT_SetIdentity
Definition: parsenodes.h:2130
@ AT_ReAddStatistics
Definition: parsenodes.h:2132
@ AT_SetUnLogged
Definition: parsenodes.h:2097
@ AT_DisableTrig
Definition: parsenodes.h:2107
@ AT_SetCompression
Definition: parsenodes.h:2079
@ AT_DropExpression
Definition: parsenodes.h:2073
@ AT_AddIndex
Definition: parsenodes.h:2081
@ AT_EnableReplicaRule
Definition: parsenodes.h:2114
@ AT_ReAddIndex
Definition: parsenodes.h:2082
@ AT_DropConstraint
Definition: parsenodes.h:2089
@ AT_SetNotNull
Definition: parsenodes.h:2072
@ AT_ClusterOn
Definition: parsenodes.h:2094
@ AT_AddIdentity
Definition: parsenodes.h:2129
@ AT_ForceRowSecurity
Definition: parsenodes.h:2123
@ AT_EnableAlwaysRule
Definition: parsenodes.h:2113
@ AT_SetAccessMethod
Definition: parsenodes.h:2099
@ AT_AlterColumnType
Definition: parsenodes.h:2091
@ AT_DetachPartitionFinalize
Definition: parsenodes.h:2128
@ AT_AddInherit
Definition: parsenodes.h:2116
@ AT_ReAddDomainConstraint
Definition: parsenodes.h:2085
@ AT_EnableTrig
Definition: parsenodes.h:2104
@ AT_DropColumn
Definition: parsenodes.h:2080
@ AT_ReAddComment
Definition: parsenodes.h:2090
@ AT_AlterColumnGenericOptions
Definition: parsenodes.h:2092
@ AT_DisableTrigAll
Definition: parsenodes.h:2109
@ AT_EnableRule
Definition: parsenodes.h:2112
@ AT_NoForceRowSecurity
Definition: parsenodes.h:2124
@ AT_DetachPartition
Definition: parsenodes.h:2127
@ AT_SetStatistics
Definition: parsenodes.h:2075
@ AT_AttachPartition
Definition: parsenodes.h:2126
@ AT_AddConstraint
Definition: parsenodes.h:2083
@ AT_DropInherit
Definition: parsenodes.h:2117
@ AT_EnableAlwaysTrig
Definition: parsenodes.h:2105
@ AT_SetLogged
Definition: parsenodes.h:2096
@ AT_SetStorage
Definition: parsenodes.h:2078
@ AT_DisableRule
Definition: parsenodes.h:2115
@ AT_DisableRowSecurity
Definition: parsenodes.h:2122
@ AT_SetRelOptions
Definition: parsenodes.h:2101
@ AT_ChangeOwner
Definition: parsenodes.h:2093
@ AT_EnableTrigUser
Definition: parsenodes.h:2110
@ AT_ReAddConstraint
Definition: parsenodes.h:2084
@ AT_SetTableSpace
Definition: parsenodes.h:2100
@ AT_GenericOptions
Definition: parsenodes.h:2125
@ AT_ColumnDefault
Definition: parsenodes.h:2069
@ AT_CookedColumnDefault
Definition: parsenodes.h:2070
@ AT_AlterConstraint
Definition: parsenodes.h:2086
@ AT_EnableTrigAll
Definition: parsenodes.h:2108
@ AT_DropCluster
Definition: parsenodes.h:2095
@ AT_ValidateConstraint
Definition: parsenodes.h:2087
@ AT_AddColumn
Definition: parsenodes.h:2067

References AT_AddColumn, AT_AddColumnToView, AT_AddConstraint, 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_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, and AT_ValidateConstraint.

Referenced by ATSimplePermissions().

◆ AlterIndexNamespaces()

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

Definition at line 16544 of file tablecmds.c.

16546 {
16547  List *indexList;
16548  ListCell *l;
16549 
16550  indexList = RelationGetIndexList(rel);
16551 
16552  foreach(l, indexList)
16553  {
16554  Oid indexOid = lfirst_oid(l);
16555  ObjectAddress thisobj;
16556 
16557  thisobj.classId = RelationRelationId;
16558  thisobj.objectId = indexOid;
16559  thisobj.objectSubId = 0;
16560 
16561  /*
16562  * Note: currently, the index will not have its own dependency on the
16563  * namespace, so we don't need to do changeDependencyFor(). There's no
16564  * row type in pg_type, either.
16565  *
16566  * XXX this objsMoved test may be pointless -- surely we have a single
16567  * dependency link from a relation to each index?
16568  */
16569  if (!object_address_present(&thisobj, objsMoved))
16570  {
16571  AlterRelationNamespaceInternal(classRel, indexOid,
16572  oldNspOid, newNspOid,
16573  false, objsMoved);
16574  add_exact_object_address(&thisobj, objsMoved);
16575  }
16576  }
16577 
16578  list_free(indexList);
16579 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2641
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2581
void list_free(List *list)
Definition: list.c:1545
#define lfirst_oid(lc)
Definition: pg_list.h:174
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4739
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16474

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

Referenced by AlterTableNamespaceInternal().

◆ AlterRelationNamespaceInternal()

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

Definition at line 16474 of file tablecmds.c.

16478 {
16479  HeapTuple classTup;
16480  Form_pg_class classForm;
16481  ObjectAddress thisobj;
16482  bool already_done = false;
16483 
16484  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
16485  if (!HeapTupleIsValid(classTup))
16486  elog(ERROR, "cache lookup failed for relation %u", relOid);
16487  classForm = (Form_pg_class) GETSTRUCT(classTup);
16488 
16489  Assert(classForm->relnamespace == oldNspOid);
16490 
16491  thisobj.classId = RelationRelationId;
16492  thisobj.objectId = relOid;
16493  thisobj.objectSubId = 0;
16494 
16495  /*
16496  * If the object has already been moved, don't move it again. If it's
16497  * already in the right place, don't move it, but still fire the object
16498  * access hook.
16499  */
16500  already_done = object_address_present(&thisobj, objsMoved);
16501  if (!already_done && oldNspOid != newNspOid)
16502  {
16503  /* check for duplicate name (more friendly than unique-index failure) */
16504  if (get_relname_relid(NameStr(classForm->relname),
16505  newNspOid) != InvalidOid)
16506  ereport(ERROR,
16507  (errcode(ERRCODE_DUPLICATE_TABLE),
16508  errmsg("relation \"%s\" already exists in schema \"%s\"",
16509  NameStr(classForm->relname),
16510  get_namespace_name(newNspOid))));
16511 
16512  /* classTup is a copy, so OK to scribble on */
16513  classForm->relnamespace = newNspOid;
16514 
16515  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
16516 
16517  /* Update dependency on schema if caller said so */
16518  if (hasDependEntry &&
16519  changeDependencyFor(RelationRelationId,
16520  relOid,
16521  NamespaceRelationId,
16522  oldNspOid,
16523  newNspOid) != 1)
16524  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
16525  NameStr(classForm->relname));
16526  }
16527  if (!already_done)
16528  {
16529  add_exact_object_address(&thisobj, objsMoved);
16530 
16531  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
16532  }
16533 
16534  heap_freetuple(classTup);
16535 }
#define NameStr(name)
Definition: c.h:730
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3331
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1867
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:456
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
@ RELOID
Definition: syscache.h:89

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

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

◆ AlterSeqNamespaces()

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

Definition at line 16589 of file tablecmds.c.

16592 {
16593  Relation depRel;
16594  SysScanDesc scan;
16595  ScanKeyData key[2];
16596  HeapTuple tup;
16597 
16598  /*
16599  * SERIAL sequences are those having an auto dependency on one of the
16600  * table's columns (we don't care *which* column, exactly).
16601  */
16602  depRel = table_open(DependRelationId, AccessShareLock);
16603 
16604  ScanKeyInit(&key[0],
16605  Anum_pg_depend_refclassid,
16606  BTEqualStrategyNumber, F_OIDEQ,
16607  ObjectIdGetDatum(RelationRelationId));
16608  ScanKeyInit(&key[1],
16609  Anum_pg_depend_refobjid,
16610  BTEqualStrategyNumber, F_OIDEQ,
16612  /* we leave refobjsubid unspecified */
16613 
16614  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
16615  NULL, 2, key);
16616 
16617  while (HeapTupleIsValid(tup = systable_getnext(scan)))
16618  {
16619  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
16620  Relation seqRel;
16621 
16622  /* skip dependencies other than auto dependencies on columns */
16623  if (depForm->refobjsubid == 0 ||
16624  depForm->classid != RelationRelationId ||
16625  depForm->objsubid != 0 ||
16626  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
16627  continue;
16628 
16629  /* Use relation_open just in case it's an index */
16630  seqRel = relation_open(depForm->objid, lockmode);
16631 
16632  /* skip non-sequence relations */
16633  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
16634  {
16635  /* No need to keep the lock */
16636  relation_close(seqRel, lockmode);
16637  continue;
16638  }
16639 
16640  /* Fix the pg_class and pg_depend entries */
16641  AlterRelationNamespaceInternal(classRel, depForm->objid,
16642  oldNspOid, newNspOid,
16643  true, objsMoved);
16644 
16645  /*
16646  * Sequences used to have entries in pg_type, but no longer do. If we
16647  * ever re-instate that, we'll need to move the pg_type entry to the
16648  * new namespace, too (using AlterTypeNamespaceInternal).
16649  */
16650  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
16651 
16652  /* Now we can close it. Keep the lock till end of transaction. */
16653  relation_close(seqRel, NoLock);
16654  }
16655 
16656  systable_endscan(scan);
16657 
16659 }
@ DEPENDENCY_AUTO
Definition: dependency.h:34
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
#define AccessShareLock
Definition: lockdefs.h:36
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
#define RelationGetForm(relation)
Definition: rel.h:497
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define BTEqualStrategyNumber
Definition: stratnum.h:31

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

Referenced by AlterTableNamespaceInternal().

◆ AlterTable()

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

Definition at line 4158 of file tablecmds.c.

4160 {
4161  Relation rel;
4162 
4163  /* Caller is required to provide an adequate lock. */
4164  rel = relation_open(context->relid, NoLock);
4165 
4166  CheckTableNotInUse(rel, "ALTER TABLE");
4167 
4168  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
4169 }
#define stmt
Definition: indent_codes.h:59
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4502

References ATController(), CheckTableNotInUse(), NoLock, relation_open(), AlterTableUtilityContext::relid, and stmt.

Referenced by ProcessUtilitySlow().

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 4232 of file tablecmds.c.

4233 {
4234  /*
4235  * This only works if we read catalog tables using MVCC snapshots.
4236  */
4237  ListCell *lcmd;
4239 
4240  foreach(lcmd, cmds)
4241  {
4242  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4243  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
4244 
4245  switch (cmd->subtype)
4246  {
4247  /*
4248  * These subcommands rewrite the heap, so require full locks.
4249  */
4250  case AT_AddColumn: /* may rewrite heap, in some cases and visible
4251  * to SELECT */
4252  case AT_SetAccessMethod: /* must rewrite heap */
4253  case AT_SetTableSpace: /* must rewrite heap */
4254  case AT_AlterColumnType: /* must rewrite heap */
4255  cmd_lockmode = AccessExclusiveLock;
4256  break;
4257 
4258  /*
4259  * These subcommands may require addition of toast tables. If
4260  * we add a toast table to a table currently being scanned, we
4261  * might miss data added to the new toast table by concurrent
4262  * insert transactions.
4263  */
4264  case AT_SetStorage: /* may add toast tables, see
4265  * ATRewriteCatalogs() */
4266  cmd_lockmode = AccessExclusiveLock;
4267  break;
4268 
4269  /*
4270  * Removing constraints can affect SELECTs that have been
4271  * optimized assuming the constraint holds true. See also
4272  * CloneFkReferenced.
4273  */
4274  case AT_DropConstraint: /* as DROP INDEX */
4275  case AT_DropNotNull: /* may change some SQL plans */
4276  cmd_lockmode = AccessExclusiveLock;
4277  break;
4278 
4279  /*
4280  * Subcommands that may be visible to concurrent SELECTs
4281  */
4282  case AT_DropColumn: /* change visible to SELECT */
4283  case AT_AddColumnToView: /* CREATE VIEW */
4284  case AT_DropOids: /* used to equiv to DropColumn */
4285  case AT_EnableAlwaysRule: /* may change SELECT rules */
4286  case AT_EnableReplicaRule: /* may change SELECT rules */
4287  case AT_EnableRule: /* may change SELECT rules */
4288  case AT_DisableRule: /* may change SELECT rules */
4289  cmd_lockmode = AccessExclusiveLock;
4290  break;
4291 
4292  /*
4293  * Changing owner may remove implicit SELECT privileges
4294  */
4295  case AT_ChangeOwner: /* change visible to SELECT */
4296  cmd_lockmode = AccessExclusiveLock;
4297  break;
4298 
4299  /*
4300  * Changing foreign table options may affect optimization.
4301  */
4302  case AT_GenericOptions:
4304  cmd_lockmode = AccessExclusiveLock;
4305  break;
4306 
4307  /*
4308  * These subcommands affect write operations only.
4309  */
4310  case AT_EnableTrig:
4311  case AT_EnableAlwaysTrig:
4312  case AT_EnableReplicaTrig:
4313  case AT_EnableTrigAll:
4314  case AT_EnableTrigUser:
4315  case AT_DisableTrig:
4316  case AT_DisableTrigAll:
4317  case AT_DisableTrigUser:
4318  cmd_lockmode = ShareRowExclusiveLock;
4319  break;
4320 
4321  /*
4322  * These subcommands affect write operations only. XXX
4323  * Theoretically, these could be ShareRowExclusiveLock.
4324  */
4325  case AT_ColumnDefault:
4327  case AT_AlterConstraint:
4328  case AT_AddIndex: /* from ADD CONSTRAINT */
4329  case AT_AddIndexConstraint:
4330  case AT_ReplicaIdentity:
4331  case AT_SetNotNull:
4332  case AT_EnableRowSecurity:
4333  case AT_DisableRowSecurity:
4334  case AT_ForceRowSecurity:
4335  case AT_NoForceRowSecurity:
4336  case AT_AddIdentity:
4337  case AT_DropIdentity:
4338  case AT_SetIdentity:
4339  case AT_DropExpression:
4340  case AT_SetCompression:
4341  cmd_lockmode = AccessExclusiveLock;
4342  break;
4343 
4344  case AT_AddConstraint:
4345  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
4346  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
4347  if (IsA(cmd->def, Constraint))
4348  {
4349  Constraint *con = (Constraint *) cmd->def;
4350 
4351  switch (con->contype)
4352  {
4353  case CONSTR_EXCLUSION:
4354  case CONSTR_PRIMARY:
4355  case CONSTR_UNIQUE:
4356 
4357  /*
4358  * Cases essentially the same as CREATE INDEX. We
4359  * could reduce the lock strength to ShareLock if
4360  * we can work out how to allow concurrent catalog
4361  * updates. XXX Might be set down to
4362  * ShareRowExclusiveLock but requires further
4363  * analysis.
4364  */
4365  cmd_lockmode = AccessExclusiveLock;
4366  break;
4367  case CONSTR_FOREIGN:
4368 
4369  /*
4370  * We add triggers to both tables when we add a
4371  * Foreign Key, so the lock level must be at least
4372  * as strong as CREATE TRIGGER.
4373  */
4374  cmd_lockmode = ShareRowExclusiveLock;
4375  break;
4376 
4377  default:
4378  cmd_lockmode = AccessExclusiveLock;
4379  }
4380  }
4381  break;
4382 
4383  /*
4384  * These subcommands affect inheritance behaviour. Queries
4385  * started before us will continue to see the old inheritance
4386  * behaviour, while queries started after we commit will see
4387  * new behaviour. No need to prevent reads or writes to the
4388  * subtable while we hook it up though. Changing the TupDesc
4389  * may be a problem, so keep highest lock.
4390  */
4391  case AT_AddInherit:
4392  case AT_DropInherit:
4393  cmd_lockmode = AccessExclusiveLock;
4394  break;
4395 
4396  /*
4397  * These subcommands affect implicit row type conversion. They
4398  * have affects similar to CREATE/DROP CAST on queries. don't
4399  * provide for invalidating parse trees as a result of such
4400  * changes, so we keep these at AccessExclusiveLock.
4401  */
4402  case AT_AddOf:
4403  case AT_DropOf:
4404  cmd_lockmode = AccessExclusiveLock;
4405  break;
4406 
4407  /*
4408  * Only used by CREATE OR REPLACE VIEW which must conflict
4409  * with an SELECTs currently using the view.
4410  */
4411  case AT_ReplaceRelOptions:
4412  cmd_lockmode = AccessExclusiveLock;
4413  break;
4414 
4415  /*
4416  * These subcommands affect general strategies for performance
4417  * and maintenance, though don't change the semantic results
4418  * from normal data reads and writes. Delaying an ALTER TABLE
4419  * behind currently active writes only delays the point where
4420  * the new strategy begins to take effect, so there is no
4421  * benefit in waiting. In this case the minimum restriction
4422  * applies: we don't currently allow concurrent catalog
4423  * updates.
4424  */
4425  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
4426  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
4427  case AT_DropCluster: /* Uses MVCC in getIndexes() */
4428  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
4429  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
4430  cmd_lockmode = ShareUpdateExclusiveLock;
4431  break;
4432 
4433  case AT_SetLogged:
4434  case AT_SetUnLogged:
4435  cmd_lockmode = AccessExclusiveLock;
4436  break;
4437 
4438  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
4439  cmd_lockmode = ShareUpdateExclusiveLock;
4440  break;
4441 
4442  /*
4443  * Rel options are more complex than first appears. Options
4444  * are set here for tables, views and indexes; for historical
4445  * reasons these can all be used with ALTER TABLE, so we can't
4446  * decide between them using the basic grammar.
4447  */
4448  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
4449  * getTables() */
4450  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
4451  * getTables() */
4452  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
4453  break;
4454 
4455  case AT_AttachPartition:
4456  cmd_lockmode = ShareUpdateExclusiveLock;
4457  break;
4458 
4459  case AT_DetachPartition:
4460  if (((PartitionCmd *) cmd->def)->concurrent)
4461  cmd_lockmode = ShareUpdateExclusiveLock;
4462  else
4463  cmd_lockmode = AccessExclusiveLock;
4464  break;
4465 
4467  cmd_lockmode = ShareUpdateExclusiveLock;
4468  break;
4469 
4470  case AT_CheckNotNull:
4471 
4472  /*
4473  * This only examines the table's schema; but lock must be
4474  * strong enough to prevent concurrent DROP NOT NULL.
4475  */
4476  cmd_lockmode = AccessShareLock;
4477  break;
4478 
4479  default: /* oops */
4480  elog(ERROR, "unrecognized alter table type: %d",
4481  (int) cmd->subtype);
4482  break;
4483  }
4484 
4485  /*
4486  * Take the greatest lockmode from any subcommand
4487  */
4488  if (cmd_lockmode > lockmode)
4489  lockmode = cmd_lockmode;
4490  }
4491 
4492  return lockmode;
4493 }
int LOCKMODE
Definition: lockdefs.h:26
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
@ CONSTR_UNIQUE
Definition: parsenodes.h:2424
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2425
@ CONSTR_PRIMARY
Definition: parsenodes.h:2423
#define lfirst(lc)
Definition: pg_list.h:172
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2109
AlterTableType subtype
Definition: parsenodes.h:2145
ConstrType contype
Definition: parsenodes.h:2450

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

Referenced by AlterTableInternal(), and ProcessUtilitySlow().

◆ AlterTableInternal()

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

Definition at line 4187 of file tablecmds.c.

4188 {
4189  Relation rel;
4190  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
4191 
4192  rel = relation_open(relid, lockmode);
4193 
4195 
4196  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
4197 }
void EventTriggerAlterTableRelid(Oid objectId)
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:4232

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 4099 of file tablecmds.c.

4100 {
4101  return RangeVarGetRelidExtended(stmt->relation, lockmode,
4102  stmt->missing_ok ? RVR_MISSING_OK : 0,
4104  (void *) stmt);
4105 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:239
@ RVR_MISSING_OK
Definition: namespace.h:71
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:17015

References RangeVarCallbackForAlterRelation(), RangeVarGetRelidExtended(), RVR_MISSING_OK, and stmt.

Referenced by ProcessUtilitySlow().

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 14540 of file tablecmds.c.

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

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, NIL, NOTICE, object_aclcheck(), OBJECT_INDEX, OBJECT_MATVIEW, object_ownercheck(), OBJECT_TABLE, OBJECT_TABLESPACE, ObjectIdGetDatum(), OidIsValid, roleSpecsToIds(), ScanKeyInit(), stmt, AlterTableCmd::subtype, table_beginscan_catalog(), table_close(), table_endscan(), and table_open().

Referenced by ProcessUtilitySlow().

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 16364 of file tablecmds.c.

16365 {
16366  Relation rel;
16367  Oid relid;
16368  Oid oldNspOid;
16369  Oid nspOid;
16370  RangeVar *newrv;
16371  ObjectAddresses *objsMoved;
16372  ObjectAddress myself;
16373 
16375  stmt->missing_ok ? RVR_MISSING_OK : 0,
16377  (void *) stmt);
16378 
16379  if (!OidIsValid(relid))
16380  {
16381  ereport(NOTICE,
16382  (errmsg("relation \"%s\" does not exist, skipping",
16383  stmt->relation->relname)));
16384  return InvalidObjectAddress;
16385  }
16386 
16387  rel = relation_open(relid, NoLock);
16388 
16389  oldNspOid = RelationGetNamespace(rel);
16390 
16391  /* If it's an owned sequence, disallow moving it by itself. */
16392  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
16393  {
16394  Oid tableId;
16395  int32 colId;
16396 
16397  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
16398  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
16399  ereport(ERROR,
16400  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
16401  errmsg("cannot move an owned sequence into another schema"),
16402  errdetail("Sequence \"%s\" is linked to table \"%s\".",
16404  get_rel_name(tableId))));
16405  }
16406 
16407  /* Get and lock schema OID and check its permissions. */
16408  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
16409  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
16410 
16411  /* common checks on switching namespaces */
16412  CheckSetNamespace(oldNspOid, nspOid);
16413 
16414  objsMoved = new_object_addresses();
16415  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
16416  free_object_addresses(objsMoved);
16417 
16418  ObjectAddressSet(myself, RelationRelationId, relid);
16419 
16420  if (oldschema)
16421  *oldschema = oldNspOid;
16422 
16423  /* close rel, but keep lock until commit */
16424  relation_close(rel, NoLock);
16425 
16426  return myself;
16427 }
signed int int32
Definition: c.h:478
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2532
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2821
int errdetail(const char *fmt,...)
Definition: elog.c:1202
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1910
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:424
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:537
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3010
const ObjectAddress InvalidObjectAddress
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:827
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16435

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

Referenced by ExecAlterObjectSchemaStmt().

◆ AlterTableNamespaceInternal()

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

Definition at line 16435 of file tablecmds.c.

16437 {
16438  Relation classRel;
16439 
16440  Assert(objsMoved != NULL);
16441 
16442  /* OK, modify the pg_class row and pg_depend entry */
16443  classRel = table_open(RelationRelationId, RowExclusiveLock);
16444 
16445  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
16446  nspOid, true, objsMoved);
16447 
16448  /* Fix the table's row type too, if it has one */
16449  if (OidIsValid(rel->rd_rel->reltype))
16450  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
16451  nspOid, false, false, objsMoved);
16452 
16453  /* Fix other dependent stuff */
16454  if (rel->rd_rel->relkind == RELKIND_RELATION ||
16455  rel->rd_rel->relkind == RELKIND_MATVIEW ||
16456  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
16457  {
16458  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
16459  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
16460  objsMoved, AccessExclusiveLock);
16461  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
16462  false, objsMoved);
16463  }
16464 
16465  table_close(classRel, RowExclusiveLock);
16466 }
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:16589
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16544
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3952

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

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

◆ ATAddCheckConstraint()

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

Definition at line 8907 of file tablecmds.c.

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

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

Referenced by ATExecAddConstraint(), and DetachAddConstraintIfNeeded().

◆ ATAddForeignKeyConstraint()

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

Definition at line 9044 of file tablecmds.c.

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

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

Referenced by ATExecAddConstraint().

◆ ATCheckPartitionsNotInUse()

static void ATCheckPartitionsNotInUse ( Relation  rel,
LOCKMODE  lockmode 
)
static

Definition at line 6402 of file tablecmds.c.

6403 {
6404  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6405  {
6406  List *inh;
6407  ListCell *cell;
6408 
6409  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
6410  /* first element is the parent rel; must ignore it */
6411  for_each_from(cell, inh, 1)
6412  {
6413  Relation childrel;
6414 
6415  /* find_all_inheritors already got lock */
6416  childrel = table_open(lfirst_oid(cell), NoLock);
6417  CheckTableNotInUse(childrel, "ALTER TABLE");
6418  table_close(childrel, NoLock);
6419  }
6420  list_free(inh);
6421  }
6422 }
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:256
#define for_each_from(cell, lst, N)
Definition: pg_list.h:414

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

Referenced by ATPrepCmd().

◆ ATColumnChangeRequiresRewrite()

static bool ATColumnChangeRequiresRewrite ( Node expr,
AttrNumber  varattno 
)
static

Definition at line 12413 of file tablecmds.c.

12414 {
12415  Assert(expr != NULL);
12416 
12417  for (;;)
12418  {
12419  /* only one varno, so no need to check that */
12420  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
12421  return false;
12422  else if (IsA(expr, RelabelType))
12423  expr = (Node *) ((RelabelType *) expr)->arg;
12424  else if (IsA(expr, CoerceToDomain))
12425  {
12426  CoerceToDomain *d = (CoerceToDomain *) expr;
12427 
12429  return true;
12430  expr = (Node *) d->arg;
12431  }
12432  else if (IsA(expr, FuncExpr))
12433  {
12434  FuncExpr *f = (FuncExpr *) expr;
12435 
12436  switch (f->funcid)
12437  {
12438  case F_TIMESTAMPTZ_TIMESTAMP:
12439  case F_TIMESTAMP_TIMESTAMPTZ:
12441  return true;
12442  else
12443  expr = linitial(f->args);
12444  break;
12445  default:
12446  return true;
12447  }
12448  }
12449  else
12450  return true;
12451  }
12452 }
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:5538
void * arg
#define linitial(l)
Definition: pg_list.h:178
Oid funcid
Definition: primnodes.h:677
List * args
Definition: primnodes.h:695
Definition: primnodes.h:226
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1392

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

Referenced by ATPrepAlterColumnType().

◆ ATController()

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

Definition at line 4502 of file tablecmds.c.

4505 {
4506  List *wqueue = NIL;
4507  ListCell *lcmd;
4508 
4509  /* Phase 1: preliminary examination of commands, create work queue */
4510  foreach(lcmd, cmds)
4511  {
4512  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4513 
4514  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4515  }
4516 
4517  /* Close the relation, but keep lock until commit */
4518  relation_close(rel, NoLock);
4519 
4520  /* Phase 2: update system catalogs */
4521  ATRewriteCatalogs(&wqueue, lockmode, context);
4522 
4523  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4524  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4525 }
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4911
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4537
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:5446

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

Referenced by AlterTable(), and AlterTableInternal().

◆ ATDetachCheckNoForeignKeyRefs()

static void ATDetachCheckNoForeignKeyRefs ( Relation  partition)
static

Definition at line 19212 of file tablecmds.c.

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

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

Referenced by ATExecDetachPartition().

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 16864 of file tablecmds.c.

16866 {
16867  ListCell *cur_item;
16868 
16869  foreach(cur_item, on_commits)
16870  {
16871  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16872 
16873  if (!isCommit && oc->creating_subid == mySubid)
16874  {
16875  /* cur_item must be removed */
16877  pfree(oc);
16878  }
16879  else
16880  {
16881  /* cur_item must be preserved */
16882  if (oc->creating_subid == mySubid)
16883  oc->creating_subid = parentSubid;
16884  if (oc->deleting_subid == mySubid)
16885  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
16886  }
16887  }
16888 }
#define InvalidSubTransactionId
Definition: c.h:642
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:390
SubTransactionId creating_subid
Definition: tablecmds.c:122
SubTransactionId deleting_subid
Definition: tablecmds.c:123
static List * on_commits
Definition: tablecmds.c:126

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 16832 of file tablecmds.c.

16833 {
16834  ListCell *cur_item;
16835 
16836  foreach(cur_item, on_commits)
16837  {
16838  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
16839 
16840  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
16842  {
16843  /* cur_item must be removed */
16845  pfree(oc);
16846  }
16847  else
16848  {
16849  /* cur_item must be preserved */
16852  }
16853  }
16854 }

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

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

◆ ATExecAddColumn()

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

Definition at line 6711 of file tablecmds.c.

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

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

Referenced by ATExecCmd().

◆ ATExecAddConstraint()

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

Definition at line 8792 of file tablecmds.c.

8795 {
8797 
8798  Assert(IsA(newConstraint, Constraint));
8799 
8800  /*
8801  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
8802  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
8803  * switch anyway to make it easier to add more code later.
8804  */
8805  switch (newConstraint->contype)
8806  {
8807  case CONSTR_CHECK:
8808  address =
8809  ATAddCheckConstraint(wqueue, tab, rel,
8810  newConstraint, recurse, false, is_readd,
8811  lockmode);
8812  break;
8813 
8814  case CONSTR_FOREIGN:
8815 
8816  /*
8817  * Assign or validate constraint name
8818  */
8819  if (newConstraint->conname)
8820  {
8822  RelationGetRelid(rel),
8823  newConstraint->conname))
8824  ereport(ERROR,
8826  errmsg("constraint \"%s\" for relation \"%s\" already exists",
8827  newConstraint->conname,
8828  RelationGetRelationName(rel))));
8829  }
8830  else
8831  newConstraint->conname =
8834  "fkey",
8835  RelationGetNamespace(rel),
8836  NIL);
8837 
8838  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
8839  newConstraint,
8840  recurse, false,
8841  lockmode);
8842  break;
8843 
8844  default:
8845  elog(ERROR, "unrecognized constraint type: %d",
8846  (int) newConstraint->contype);
8847  }
8848 
8849  return address;
8850 }
@ CONSTR_CHECK
Definition: parsenodes.h:2422
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:9044

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

Referenced by ATExecCmd().

◆ ATExecAddIdentity()

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

Definition at line 7712 of file tablecmds.c.

7714 {
7715  Relation attrelation;
7716  HeapTuple tuple;
7717  Form_pg_attribute attTup;
7719  ObjectAddress address;
7720  ColumnDef *cdef = castNode(ColumnDef, def);
7721 
7722  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7723 
7724  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7725  if (!HeapTupleIsValid(tuple))
7726  ereport(ERROR,
7727  (errcode(ERRCODE_UNDEFINED_COLUMN),
7728  errmsg("column \"%s\" of relation \"%s\" does not exist",
7729  colName, RelationGetRelationName(rel))));
7730  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7731  attnum = attTup->attnum;
7732 
7733  /* Can't alter a system attribute */
7734  if (attnum <= 0)
7735  ereport(ERROR,
7736  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7737  errmsg("cannot alter system column \"%s\"",
7738  colName)));
7739 
7740  /*
7741  * Creating a column as identity implies NOT NULL, so adding the identity
7742  * to an existing column that is not NOT NULL would create a state that
7743  * cannot be reproduced without contortions.
7744  */
7745  if (!attTup->attnotnull)
7746  ereport(ERROR,
7747  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7748  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
7749  colName, RelationGetRelationName(rel))));
7750 
7751  if (attTup->attidentity)
7752  ereport(ERROR,
7753  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7754  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
7755  colName, RelationGetRelationName(rel))));
7756 
7757  if (attTup->atthasdef)
7758  ereport(ERROR,
7759  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7760  errmsg("column \"%s\" of relation \"%s\" already has a default value",
7761  colName, RelationGetRelationName(rel))));
7762 
7763  attTup->attidentity = cdef->identity;
7764  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7765 
7766  InvokeObjectPostAlterHook(RelationRelationId,
7767  RelationGetRelid(rel),
7768  attTup->attnum);
7769  ObjectAddressSubSet(address, RelationRelationId,
7770  RelationGetRelid(rel), attnum);
7771  heap_freetuple(tuple);
7772 
7773  table_close(attrelation, RowExclusiveLock);
7774 
7775  return address;
7776 }

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

Referenced by ATExecCmd().

◆ ATExecAddIndex()

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

Definition at line 8617 of file tablecmds.c.

8619 {
8620  bool check_rights;
8621  bool skip_build;
8622  bool quiet;
8623  ObjectAddress address;
8624 
8625  Assert(IsA(stmt, IndexStmt));
8626  Assert(!stmt->concurrent);
8627 
8628  /* The IndexStmt has already been through transformIndexStmt */
8629  Assert(stmt->transformed);
8630 
8631  /* suppress schema rights check when rebuilding existing index */
8632  check_rights = !is_rebuild;
8633  /* skip index build if phase 3 will do it or we're reusing an old one */
8634  skip_build = tab->rewrite > 0 || RelFileNumberIsValid(stmt->oldNumber);
8635  /* suppress notices when rebuilding existing index */
8636  quiet = is_rebuild;
8637 
8638  address = DefineIndex(RelationGetRelid(rel),
8639  stmt,
8640  InvalidOid, /* no predefined OID */
8641  InvalidOid, /* no parent index */
8642  InvalidOid, /* no parent constraint */
8643  true, /* is_alter_table */
8644  check_rights,
8645  false, /* check_not_in_use - we did it already */
8646  skip_build,
8647  quiet);
8648 
8649  /*
8650  * If TryReuseIndex() stashed a relfilenumber for us, we used it for the
8651  * new index instead of building from scratch. Restore associated fields.
8652  * This may store InvalidSubTransactionId in both fields, in which case
8653  * relcache.c will assume it can rebuild the relcache entry. Hence, do
8654  * this after the CCI that made catalog rows visible to any rebuild. The
8655  * DROP of the old edition of this index will have scheduled the storage
8656  * for deletion at commit, so cancel that pending deletion.
8657  */
8658  if (RelFileNumberIsValid(stmt->oldNumber))
8659  {
8660  Relation irel = index_open(address.objectId, NoLock);
8661 
8662  irel->rd_createSubid = stmt->oldCreateSubid;
8663  irel->rd_firstRelfilelocatorSubid = stmt->oldFirstRelfilelocatorSubid;
8664  RelationPreserveStorage(irel->rd_locator, true);
8665  index_close(irel, NoLock);
8666  }
8667 
8668  return address;
8669 }
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
ObjectAddress DefineIndex(Oid relationId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition: indexcmds.c:528
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
void RelationPreserveStorage(RelFileLocator rlocator, bool atCommit)
Definition: storage.c:250
SubTransactionId rd_firstRelfilelocatorSubid
Definition: rel.h:105
SubTransactionId rd_createSubid
Definition: rel.h:102
RelFileLocator rd_locator
Definition: rel.h:56

References Assert(), DefineIndex(), index_close(), index_open(), InvalidOid, IsA, NoLock, ObjectAddress::objectId, RelationData::rd_createSubid, RelationData::rd_firstRelfilelocatorSubid, RelationData::rd_locator, RelationGetRelid, RelationPreserveStorage(), RelFileNumberIsValid, AlteredTableInfo::rewrite, and stmt.

Referenced by ATExecCmd().

◆ ATExecAddIndexConstraint()

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

Definition at line 8700 of file tablecmds.c.

8702 {
8703  Oid index_oid = stmt->indexOid;
8704  Relation indexRel;
8705  char *indexName;
8706  IndexInfo *indexInfo;
8707  char *constraintName;
8708  char constraintType;
8709  ObjectAddress address;
8710  bits16 flags;
8711 
8712  Assert(IsA(stmt, IndexStmt));
8713  Assert(OidIsValid(index_oid));
8714  Assert(stmt->isconstraint);
8715 
8716  /*
8717  * Doing this on partitioned tables is not a simple feature to implement,
8718  * so let's punt for now.
8719  */
8720  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8721  ereport(ERROR,
8722  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8723  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
8724 
8725  indexRel = index_open(index_oid, AccessShareLock);
8726 
8727  indexName = pstrdup(RelationGetRelationName(indexRel));
8728 
8729  indexInfo = BuildIndexInfo(indexRel);
8730 
8731  /* this should have been checked at parse time */
8732  if (!indexInfo->ii_Unique)
8733  elog(ERROR, "index \"%s\" is not unique", indexName);
8734 
8735  /*
8736  * Determine name to assign to constraint. We require a constraint to
8737  * have the same name as the underlying index; therefore, use the index's
8738  * existing name as the default constraint name, and if the user
8739  * explicitly gives some other name for the constraint, rename the index
8740  * to match.
8741  */
8742  constraintName = stmt->idxname;
8743  if (constraintName == NULL)
8744  constraintName = indexName;
8745  else if (strcmp(constraintName, indexName) != 0)
8746  {
8747  ereport(NOTICE,
8748  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
8749  indexName, constraintName)));
8750  RenameRelationInternal(index_oid, constraintName, false, true);
8751  }
8752 
8753  /* Extra checks needed if making primary key */
8754  if (stmt->primary)
8755  index_check_primary_key(rel, indexInfo, true, stmt);
8756 
8757  /* Note we currently don't support EXCLUSION constraints here */
8758  if (stmt->primary)
8759  constraintType = CONSTRAINT_PRIMARY;
8760  else
8761  constraintType = CONSTRAINT_UNIQUE;
8762 
8763  /* Create the catalog entries for the constraint */
8766  (stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
8767  (stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
8768  (stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
8769 
8770  address = index_constraint_create(rel,
8771  index_oid,
8772  InvalidOid,
8773  indexInfo,
8774  constraintName,
8775  constraintType,
8776  flags,
8778  false); /* is_internal */
8779 
8780  index_close(indexRel, NoLock);
8781 
8782  return address;
8783 }
uint16 bits16
Definition: c.h:498
ObjectAddress index_constraint_create(Relation heapRelation, Oid indexRelationId, Oid parentConstraintId, IndexInfo *indexInfo, const char *constraintName, char constraintType, bits16 constr_flags, bool allow_system_table_mods, bool is_internal)
Definition: index.c:1911
void index_check_primary_key(Relation heapRel, IndexInfo *indexInfo, bool is_alter_table, IndexStmt *stmt)
Definition: index.c:206
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2434
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:92
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:93
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:90
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition: index.h:89
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:91
char * pstrdup(const char *in)
Definition: mcxt.c:1624
bool ii_Unique
Definition: execnodes.h:191
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3928

References AccessShareLock, allowSystemTableMods, Assert(), BuildIndexInfo(), elog(), ereport, errcode(), errmsg(), ERROR, IndexInfo::ii_Unique, index_check_primary_key(), index_close(), INDEX_CONSTR_CREATE_DEFERRABLE, INDEX_CONSTR_CREATE_INIT_DEFERRED, INDEX_CONSTR_CREATE_MARK_AS_PRIMARY, INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS, INDEX_CONSTR_CREATE_UPDATE_INDEX, index_constraint_create(), index_open(), InvalidOid, IsA, NoLock, NOTICE, OidIsValid, pstrdup(), RelationData::rd_rel, RelationGetRelationName, RenameRelationInternal(), and stmt.

Referenced by ATExecCmd().

◆ ATExecAddInherit()

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

Definition at line 14812 of file tablecmds.c.

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

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

Referenced by ATExecCmd().

◆ ATExecAddOf()

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

Definition at line 15650 of file tablecmds.c.

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

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

Referenced by ATExecCmd().

◆ ATExecAddStatistics()

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

Definition at line 8679 of file tablecmds.c.

8681 {
8682  ObjectAddress address;
8683 
8685 
8686  /* The CreateStatsStmt has already been through transformStatsStmt */
8687  Assert(stmt->transformed);
8688 
8689  address = CreateStatistics(stmt);
8690 
8691  return address;
8692 }
ObjectAddress CreateStatistics(CreateStatsStmt *stmt)
Definition: statscmds.c:65

References Assert(), CreateStatistics(), IsA, and stmt.

Referenced by ATExecCmd().

◆ ATExecAlterColumnGenericOptions()

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

Definition at line 13622 of file tablecmds.c.

13626 {
13627  Relation ftrel;
13628  Relation attrel;
13629  ForeignServer *server;
13630  ForeignDataWrapper *fdw;
13631  HeapTuple tuple;
13632  HeapTuple newtuple;
13633  bool isnull;
13634  Datum repl_val[Natts_pg_attribute];
13635  bool repl_null[Natts_pg_attribute];
13636  bool repl_repl[Natts_pg_attribute];
13637  Datum datum;
13638  Form_pg_foreign_table fttableform;
13639  Form_pg_attribute atttableform;
13641  ObjectAddress address;
13642 
13643  if (options == NIL)
13644  return InvalidObjectAddress;
13645 
13646  /* First, determine FDW validator associated to the foreign table. */
13647  ftrel = table_open(ForeignTableRelationId, AccessShareLock);
13648  tuple = SearchSysCache1(FOREIGNTABLEREL, rel->rd_id);
13649  if (!HeapTupleIsValid(tuple))
13650  ereport(ERROR,
13651  (errcode(ERRCODE_UNDEFINED_OBJECT),
13652  errmsg("foreign table \"%s\" does not exist",
13653  RelationGetRelationName(rel))));
13654  fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
13655  server = GetForeignServer(fttableform->ftserver);
13656  fdw = GetForeignDataWrapper(server->fdwid);
13657 
13658  table_close(ftrel, AccessShareLock);
13659  ReleaseSysCache(tuple);
13660 
13661  attrel = table_open(AttributeRelationId, RowExclusiveLock);
13662  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
13663  if (!HeapTupleIsValid(tuple))
13664  ereport(ERROR,
13665  (errcode(ERRCODE_UNDEFINED_COLUMN),
13666  errmsg("column \"%s\" of relation \"%s\" does not exist",
13667  colName, RelationGetRelationName(rel))));
13668 
13669  /* Prevent them from altering a system attribute */
13670  atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
13671  attnum = atttableform->attnum;
13672  if (attnum <= 0)
13673  ereport(ERROR,
13674  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13675  errmsg("cannot alter system column \"%s\"", colName)));
13676 
13677 
13678  /* Initialize buffers for new tuple values */
13679  memset(repl_val, 0, sizeof(repl_val));
13680  memset(repl_null, false, sizeof(repl_null));
13681  memset(repl_repl, false, sizeof(repl_repl));
13682 
13683  /* Extract the current options */
13684  datum =