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/xact.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_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/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  AttachIndexCallbackState
 

Macros

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

Typedefs

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

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 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, Relation rel, 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 (Relation rel, int allowed_targets)
 
static void ATWrongRelkindError (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 recursing)
 
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 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, Oid parentConstr, bool recurse, bool recursing, LOCKMODE lockmode)
 
static ObjectAddress addFkRecurseReferenced (List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok)
 
static void addFkRecurseReferencing (List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok, LOCKMODE lockmode)
 
static void CloneForeignKeyConstraints (List **wqueue, Relation parentRel, Relation partitionRel)
 
static void CloneFkReferenced (Relation parentRel, Relation partitionRel)
 
static void CloneFkReferencing (List **wqueue, Relation parentRel, Relation partRel)
 
static void createForeignKeyCheckTriggers (Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
 
static void createForeignKeyActionTriggers (Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
 
static bool tryAttachPartitionForeignKey (ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop)
 
static void ATExecDropConstraint (Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode)
 
static void ATPrepAlterColumnType (List **wqueue, AlteredTableInfo *tab, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static bool ATColumnChangeRequiresRewrite (Node *expr, AttrNumber varattno)
 
static ObjectAddress ATExecAlterColumnType (AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static void RememberConstraintForRebuilding (Oid conoid, AlteredTableInfo *tab)
 
static void RememberIndexForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
static void 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 bool ATPrepChangePersistence (Relation rel, bool toLogged)
 
static void ATPrepSetTableSpace (AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode)
 
static void ATExecSetTableSpace (Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 
static void ATExecSetTableSpaceNoStorage (Relation rel, Oid newTableSpace)
 
static void ATExecSetRelOptions (Relation rel, List *defList, AlterTableType operation, LOCKMODE lockmode)
 
static void ATExecEnableDisableTrigger (Relation rel, const char *trigname, char fires_when, bool skip_system, LOCKMODE lockmode)
 
static void ATExecEnableDisableRule (Relation rel, const char *rulename, char fires_when, LOCKMODE lockmode)
 
static void ATPrepAddInherit (Relation child_rel)
 
static ObjectAddress ATExecAddInherit (Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
 
static ObjectAddress ATExecDropInherit (Relation rel, RangeVar *parent, LOCKMODE lockmode)
 
static void drop_parent_dependency (Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
 
static ObjectAddress ATExecAddOf (Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
 
static void ATExecDropOf (Relation rel, LOCKMODE lockmode)
 
static void ATExecReplicaIdentity (Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
 
static void ATExecGenericOptions (Relation rel, List *options)
 
static void ATExecEnableRowSecurity (Relation rel)
 
static void ATExecDisableRowSecurity (Relation rel)
 
static void ATExecForceNoForceRowSecurity (Relation rel, bool force_rls)
 
static void index_copy_data (Relation rel, RelFileNode newrnode)
 
static const char * storage_name (char c)
 
static void RangeVarCallbackForDropRelation (const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
 
static void RangeVarCallbackForAlterRelation (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
static PartitionSpectransformPartitionSpec (Relation rel, PartitionSpec *partspec, char *strategy)
 
static void ComputePartitionAttrs (ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, char strategy)
 
static void CreateInheritance (Relation child_rel, Relation parent_rel)
 
static void RemoveInheritance (Relation child_rel, Relation parent_rel)
 
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 DropClonedTriggersFromPartition (Oid partitionId)
 
static ObjectAddress ATExecDetachPartition (Relation rel, RangeVar *name)
 
static ObjectAddress ATExecAttachPartitionIdx (List **wqueue, Relation rel, RangeVar *name)
 
static void validatePartitionedIndex (Relation partedIdx, Relation partedTbl)
 
static void refuseDupeIndexAttach (Relation parentIdx, Relation partIdx, Relation partitionTbl)
 
static ListGetParentedForeignKeyRefs (Relation partition)
 
static void ATDetachCheckNoForeignKeyRefs (Relation partition)
 
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)
 
static void renameatt_check (Oid myrelid, Form_pg_class classform, bool recursing)
 
static AttrNumber renameatt_internal (Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
 
static void RangeVarCallbackForRenameAttribute (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
ObjectAddress renameatt (RenameStmt *stmt)
 
static ObjectAddress rename_constraint_internal (Oid myrelid, Oid mytypid, const char *oldconname, const char *newconname, bool recurse, bool recursing, int expected_parents)
 
ObjectAddress RenameConstraint (RenameStmt *stmt)
 
ObjectAddress RenameRelation (RenameStmt *stmt)
 
void RenameRelationInternal (Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
 
void CheckTableNotInUse (Relation rel, const char *stmt)
 
Oid AlterTableLookupRelation (AlterTableStmt *stmt, LOCKMODE lockmode)
 
void AlterTable (AlterTableStmt *stmt, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
void AlterTableInternal (Oid relid, List *cmds, bool recurse)
 
LOCKMODE AlterTableGetLockLevel (List *cmds)
 
void find_composite_type_dependencies (Oid typeOid, Relation origRelation, const char *origTypeName)
 
void check_of_type (HeapTuple typetuple)
 
static void CreateFKCheckTrigger (Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, bool on_insert)
 
static void RememberReplicaIdentityForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
static void RememberClusterOnForRebuilding (Oid indoid, AlteredTableInfo *tab)
 
void ATExecChangeOwner (Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
 
Oid AlterTableMoveAll (AlterTableMoveAllStmt *stmt)
 
static char * decompile_conbin (HeapTuple contup, TupleDesc tupdesc)
 
static bool constraints_equivalent (HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
 
static void relation_mark_replica_identity (Relation rel, char ri_type, Oid indexOid, bool is_internal)
 
ObjectAddress AlterTableNamespace (AlterObjectSchemaStmt *stmt, Oid *oldschema)
 
void AlterTableNamespaceInternal (Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
 
void AlterRelationNamespaceInternal (Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
 
void register_on_commit_action (Oid relid, OnCommitAction action)
 
void remove_on_commit_action (Oid relid)
 
void PreCommit_on_commit_actions (void)
 
void AtEOXact_on_commit_actions (bool isCommit)
 
void AtEOSubXact_on_commit_actions (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
void RangeVarCallbackOwnsTable (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
void RangeVarCallbackOwnsRelation (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
bool PartConstraintImpliedByRelConstraint (Relation scanrel, List *partConstraint)
 
static void RangeVarCallbackForAttachIndex (const RangeVar *rv, Oid relOid, Oid oldRelOid, void *arg)
 

Variables

static Liston_commits = NIL
 
static const struct dropmsgstrings dropmsgstringarray []
 

Macro Definition Documentation

◆ AT_NUM_PASSES

#define AT_NUM_PASSES   11

Definition at line 152 of file tablecmds.c.

Referenced by ATRewriteCatalogs().

◆ AT_PASS_ADD_COL

#define AT_PASS_ADD_COL   4 /* ADD COLUMN */

Definition at line 145 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_ADD_CONSTR

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

Definition at line 146 of file tablecmds.c.

Referenced by ATExecCmd(), and ATPrepCmd().

◆ AT_PASS_ADD_INDEX

#define AT_PASS_ADD_INDEX   8 /* ADD indexes */

Definition at line 149 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_ADD_INDEXCONSTR

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

Definition at line 148 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_ADD_OTHERCONSTR

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

Definition at line 150 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_ALTER_TYPE

#define AT_PASS_ALTER_TYPE   1 /* ALTER COLUMN TYPE */

Definition at line 141 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATRewriteCatalogs().

◆ AT_PASS_COL_ATTRS

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

Definition at line 147 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_DROP

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

Definition at line 140 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_MISC

#define AT_PASS_MISC   10 /* other stuff */

Definition at line 151 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_OLD_CONSTR

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

Definition at line 143 of file tablecmds.c.

Referenced by ATPostAlterTypeCleanup(), and ATPostAlterTypeParse().

◆ AT_PASS_OLD_INDEX

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

Definition at line 142 of file tablecmds.c.

Referenced by ATPostAlterTypeParse().

◆ AT_PASS_UNSET

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

Definition at line 139 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ ATT_COMPOSITE_TYPE

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 296 of file tablecmds.c.

Referenced by ATPrepCmd(), ATSimplePermissions(), and ATWrongRelkindError().

◆ ATT_FOREIGN_TABLE

◆ ATT_INDEX

#define ATT_INDEX   0x0008

Definition at line 295 of file tablecmds.c.

Referenced by ATPrepCmd(), ATSimplePermissions(), and ATWrongRelkindError().

◆ ATT_MATVIEW

#define ATT_MATVIEW   0x0004

Definition at line 294 of file tablecmds.c.

Referenced by ATPrepCmd(), ATSimplePermissions(), and ATWrongRelkindError().

◆ ATT_PARTITIONED_INDEX

#define ATT_PARTITIONED_INDEX   0x0040

Definition at line 298 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATSimplePermissions().

◆ ATT_TABLE

◆ ATT_VIEW

#define ATT_VIEW   0x0002

Definition at line 293 of file tablecmds.c.

Referenced by ATPrepCmd(), ATSimplePermissions(), and ATWrongRelkindError().

◆ child_dependency_type

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

Definition at line 305 of file tablecmds.c.

Referenced by RemoveInheritance(), and StoreCatalogInheritance1().

Typedef Documentation

◆ AlteredTableInfo

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

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

6517 {
6518  ObjectAddress myself,
6519  referenced;
6520 
6521  /* We know the default collation is pinned, so don't bother recording it */
6522  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
6523  {
6524  myself.classId = RelationRelationId;
6525  myself.objectId = relid;
6526  myself.objectSubId = attnum;
6527  referenced.classId = CollationRelationId;
6528  referenced.objectId = collid;
6529  referenced.objectSubId = 0;
6530  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
6531  }
6532 }
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
#define OidIsValid(objectId)
Definition: c.h:651
int16 attnum
Definition: pg_attribute.h:79

◆ add_column_datatype_dependency()

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

Definition at line 6498 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

6499 {
6500  ObjectAddress myself,
6501  referenced;
6502 
6503  myself.classId = RelationRelationId;
6504  myself.objectId = relid;
6505  myself.objectSubId = attnum;
6506  referenced.classId = TypeRelationId;
6507  referenced.objectId = typid;
6508  referenced.objectSubId = 0;
6509  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
6510 }
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
int16 attnum
Definition: pg_attribute.h:79

◆ addFkRecurseReferenced()

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

Definition at line 8777 of file tablecmds.c.

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

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferenced().

8782 {
8783  ObjectAddress address;
8784  Oid constrOid;
8785  char *conname;
8786  bool conislocal;
8787  int coninhcount;
8788  bool connoinherit;
8789 
8790  /*
8791  * Verify relkind for each referenced partition. At the top level, this
8792  * is redundant with a previous check, but we need it when recursing.
8793  */
8794  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
8795  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
8796  ereport(ERROR,
8797  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8798  errmsg("referenced relation \"%s\" is not a table",
8799  RelationGetRelationName(pkrel))));
8800 
8801  /*
8802  * Caller supplies us with a constraint name; however, it may be used in
8803  * this partition, so come up with a different one in that case.
8804  */
8806  RelationGetRelid(rel),
8807  fkconstraint->conname))
8810  "fkey",
8811  RelationGetNamespace(rel), NIL);
8812  else
8813  conname = fkconstraint->conname;
8814 
8815  if (OidIsValid(parentConstr))
8816  {
8817  conislocal = false;
8818  coninhcount = 1;
8819  connoinherit = false;
8820  }
8821  else
8822  {
8823  conislocal = true;
8824  coninhcount = 0;
8825 
8826  /*
8827  * always inherit for partitioned tables, never for legacy inheritance
8828  */
8829  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
8830  }
8831 
8832  /*
8833  * Record the FK constraint in pg_constraint.
8834  */
8835  constrOid = CreateConstraintEntry(conname,
8836  RelationGetNamespace(rel),
8837  CONSTRAINT_FOREIGN,
8838  fkconstraint->deferrable,
8839  fkconstraint->initdeferred,
8840  fkconstraint->initially_valid,
8841  parentConstr,
8842  RelationGetRelid(rel),
8843  fkattnum,
8844  numfks,
8845  numfks,
8846  InvalidOid, /* not a domain constraint */
8847  indexOid,
8848  RelationGetRelid(pkrel),
8849  pkattnum,
8850  pfeqoperators,
8851  ppeqoperators,
8852  ffeqoperators,
8853  numfks,
8854  fkconstraint->fk_upd_action,
8855  fkconstraint->fk_del_action,
8856  fkconstraint->fk_matchtype,
8857  NULL, /* no exclusion constraint */
8858  NULL, /* no check constraint */
8859  NULL,
8860  conislocal, /* islocal */
8861  coninhcount, /* inhcount */
8862  connoinherit, /* conNoInherit */
8863  false); /* is_internal */
8864 
8865  ObjectAddressSet(address, ConstraintRelationId, constrOid);
8866 
8867  /*
8868  * Mark the child constraint as part of the parent constraint; it must not
8869  * be dropped on its own. (This constraint is deleted when the partition
8870  * is detached, but a special check needs to occur that the partition
8871  * contains no referenced values.)
8872  */
8873  if (OidIsValid(parentConstr))
8874  {
8875  ObjectAddress referenced;
8876 
8877  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
8878  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
8879  }
8880 
8881  /* make new constraint visible, in case we add more */
8883 
8884  /*
8885  * If the referenced table is a plain relation, create the action triggers
8886  * that enforce the constraint.
8887  */
8888  if (pkrel->rd_rel->relkind == RELKIND_RELATION)
8889  {
8891  fkconstraint,
8892  constrOid, indexOid);
8893  }
8894 
8895  /*
8896  * If the referenced table is partitioned, recurse on ourselves to handle
8897  * each partition. We need one pg_constraint row created for each
8898  * partition in addition to the pg_constraint row for the parent table.
8899  */
8900  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8901  {
8903 
8904  for (int i = 0; i < pd->nparts; i++)
8905  {
8906  Relation partRel;
8907  AttrMap *map;
8908  AttrNumber *mapped_pkattnum;
8909  Oid partIndexId;
8910 
8911  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
8912 
8913  /*
8914  * Map the attribute numbers in the referenced side of the FK
8915  * definition to match the partition's column layout.
8916  */
8918  RelationGetDescr(pkrel));
8919  if (map)
8920  {
8921  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
8922  for (int j = 0; j < numfks; j++)
8923  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
8924  }
8925  else
8926  mapped_pkattnum = pkattnum;
8927 
8928  /* do the deed */
8929  partIndexId = index_get_partition(partRel, indexOid);
8930  if (!OidIsValid(partIndexId))
8931  elog(ERROR, "index for %u not found in partition %s",
8932  indexOid, RelationGetRelationName(partRel));
8933  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
8934  partIndexId, constrOid, numfks,
8935  mapped_pkattnum, fkattnum,
8936  pfeqoperators, ppeqoperators, ffeqoperators,
8937  old_check_ok);
8938 
8939  /* Done -- clean up (but keep the lock) */
8940  table_close(partRel, NoLock);
8941  if (map)
8942  {
8943  pfree(mapped_pkattnum);
8944  free_attrmap(map);
8945  }
8946  }
8947  }
8948 
8949  return address;
8950 }
#define NIL
Definition: pg_list.h:65
Oid index_get_partition(Relation partition, Oid indexId)
Definition: partition.c:153
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8160
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void free_attrmap(AttrMap *map)
Definition: attmap.c:57
#define RelationGetDescr(relation)
Definition: rel.h:482
char fk_matchtype
Definition: parsenodes.h:2191
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:50
int errcode(int sqlerrcode)
Definition: elog.c:610
bool initdeferred
Definition: parsenodes.h:2159
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
char * conname
Definition: parsenodes.h:2157
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:651
Definition: attmap.h:34
void pfree(void *pointer)
Definition: mcxt.c:1057
static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok)
Definition: tablecmds.c:8777
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:259
#define ERROR
Definition: elog.h:43
bool deferrable
Definition: parsenodes.h:2158
#define NoLock
Definition: lockdefs.h:34
PartitionDesc RelationGetPartitionDesc(Relation rel)
Definition: partdesc.c:65
#define RelationGetRelationName(relation)
Definition: rel.h:490
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:10555
void CommandCounterIncrement(void)
Definition: xact.c:1021
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2200
#define ereport(elevel,...)
Definition: elog.h:144
char fk_del_action
Definition: parsenodes.h:2193
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
AttrNumber * attnums
Definition: attmap.h:36
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
int i
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:456
List * fk_attrs
Definition: parsenodes.h:2189
char fk_upd_action
Definition: parsenodes.h:2192
#define RelationGetNamespace(relation)
Definition: rel.h:497

◆ addFkRecurseReferencing()

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

Definition at line 8982 of file tablecmds.c.

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

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferencing().

8987 {
8988  AssertArg(OidIsValid(parentConstr));
8989 
8990  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
8991  ereport(ERROR,
8992  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8993  errmsg("foreign key constraints are not supported on foreign tables")));
8994 
8995  /*
8996  * If the referencing relation is a plain table, add the check triggers to
8997  * it and, if necessary, schedule it to be checked in Phase 3.
8998  *
8999  * If the relation is partitioned, drill down to do it to its partitions.
9000  */
9001  if (rel->rd_rel->relkind == RELKIND_RELATION)
9002  {
9004  RelationGetRelid(pkrel),
9005  fkconstraint,
9006  parentConstr,
9007  indexOid);
9008 
9009  /*
9010  * Tell Phase 3 to check that the constraint is satisfied by existing
9011  * rows. We can skip this during table creation, when requested
9012  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
9013  * and when we're recreating a constraint following a SET DATA TYPE
9014  * operation that did not impugn its validity.
9015  */
9016  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
9017  {
9018  NewConstraint *newcon;
9019  AlteredTableInfo *tab;
9020 
9021  tab = ATGetQueueEntry(wqueue, rel);
9022 
9023  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9024  newcon->name = get_constraint_name(parentConstr);
9025  newcon->contype = CONSTR_FOREIGN;
9026  newcon->refrelid = RelationGetRelid(pkrel);
9027  newcon->refindid = indexOid;
9028  newcon->conid = parentConstr;
9029  newcon->qual = (Node *) fkconstraint;
9030 
9031  tab->constraints = lappend(tab->constraints, newcon);
9032  }
9033  }
9034  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9035  {
9037 
9038  /*
9039  * Recurse to take appropriate action on each partition; either we
9040  * find an existing constraint to reparent to ours, or we create a new
9041  * one.
9042  */
9043  for (int i = 0; i < pd->nparts; i++)
9044  {
9045  Oid partitionId = pd->oids[i];
9046  Relation partition = table_open(partitionId, lockmode);
9047  List *partFKs;
9048  AttrMap *attmap;
9049  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
9050  bool attached;
9051  char *conname;
9052  Oid constrOid;
9053  ObjectAddress address,
9054  referenced;
9055  ListCell *cell;
9056 
9057  CheckTableNotInUse(partition, "ALTER TABLE");
9058 
9059  attmap = build_attrmap_by_name(RelationGetDescr(partition),
9060  RelationGetDescr(rel));
9061  for (int j = 0; j < numfks; j++)
9062  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
9063 
9064  /* Check whether an existing constraint can be repurposed */
9065  partFKs = copyObject(RelationGetFKeyList(partition));
9066  attached = false;
9067  foreach(cell, partFKs)
9068  {
9069  ForeignKeyCacheInfo *fk;
9070 
9071  fk = lfirst_node(ForeignKeyCacheInfo, cell);
9073  partitionId,
9074  parentConstr,
9075  numfks,
9076  mapped_fkattnum,
9077  pkattnum,
9078  pfeqoperators))
9079  {
9080  attached = true;
9081  break;
9082  }
9083  }
9084  if (attached)
9085  {
9086  table_close(partition, NoLock);
9087  continue;
9088  }
9089 
9090  /*
9091  * No luck finding a good constraint to reuse; create our own.
9092  */
9094  RelationGetRelid(partition),
9095  fkconstraint->conname))
9096  conname = ChooseConstraintName(RelationGetRelationName(partition),
9098  "fkey",
9099  RelationGetNamespace(partition), NIL);
9100  else
9101  conname = fkconstraint->conname;
9102  constrOid =
9103  CreateConstraintEntry(conname,
9104  RelationGetNamespace(partition),
9105  CONSTRAINT_FOREIGN,
9106  fkconstraint->deferrable,
9107  fkconstraint->initdeferred,
9108  fkconstraint->initially_valid,
9109  parentConstr,
9110  partitionId,
9111  mapped_fkattnum,
9112  numfks,
9113  numfks,
9114  InvalidOid,
9115  indexOid,
9116  RelationGetRelid(pkrel),
9117  pkattnum,
9118  pfeqoperators,
9119  ppeqoperators,
9120  ffeqoperators,
9121  numfks,
9122  fkconstraint->fk_upd_action,
9123  fkconstraint->fk_del_action,
9124  fkconstraint->fk_matchtype,
9125  NULL,
9126  NULL,
9127  NULL,
9128  false,
9129  1,
9130  false,
9131  false);
9132 
9133  /*
9134  * Give this constraint partition-type dependencies on the parent
9135  * constraint as well as the table.
9136  */
9137  ObjectAddressSet(address, ConstraintRelationId, constrOid);
9138  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9139  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
9140  ObjectAddressSet(referenced, RelationRelationId, partitionId);
9141  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
9142 
9143  /* Make all this visible before recursing */
9145 
9146  /* call ourselves to finalize the creation and we're done */
9147  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
9148  indexOid,
9149  constrOid,
9150  numfks,
9151  pkattnum,
9152  mapped_fkattnum,
9153  pfeqoperators,
9154  ppeqoperators,
9155  ffeqoperators,
9156  old_check_ok,
9157  lockmode);
9158 
9159  table_close(partition, NoLock);
9160  }
9161  }
9162 }
#define NIL
Definition: pg_list.h:65
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:10676
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
char * name
Definition: tablecmds.c:187
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8160
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define RelationGetDescr(relation)
Definition: rel.h:482
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:1079
static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok, LOCKMODE lockmode)
Definition: tablecmds.c:8982
char fk_matchtype
Definition: parsenodes.h:2191
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:50
Node * qual
Definition: tablecmds.c:192
Definition: nodes.h:528
int errcode(int sqlerrcode)
Definition: elog.c:610
bool initdeferred
Definition: parsenodes.h:2159
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
char * conname
Definition: parsenodes.h:2157
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:651
List * constraints
Definition: tablecmds.c:163
Definition: attmap.h:34
static bool tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop)
Definition: tablecmds.c:9579
#define ERROR
Definition: elog.h:43
bool deferrable
Definition: parsenodes.h:2158
#define lfirst_node(type, lc)
Definition: pg_list.h:172
#define NoLock
Definition: lockdefs.h:34
PartitionDesc RelationGetPartitionDesc(Relation rel)
Definition: partdesc.c:65
#define RelationGetRelationName(relation)
Definition: rel.h:490
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5526
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3589
#define AssertArg(condition)
Definition: c.h:747
List * lappend(List *list, void *datum)
Definition: list.c:321
ConstrType contype
Definition: tablecmds.c:188
void * palloc0(Size size)
Definition: mcxt.c:981
void CommandCounterIncrement(void)
Definition: xact.c:1021
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2200
#define ereport(elevel,...)
Definition: elog.h:144
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:174
char fk_del_action
Definition: parsenodes.h:2193
AttrNumber * attnums
Definition: attmap.h:36
#define INDEX_MAX_KEYS
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4405
int errmsg(const char *fmt,...)
Definition: elog.c:824
int i
#define copyObject(obj)
Definition: nodes.h:644
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
bool skip_validation
Definition: parsenodes.h:2199
#define RelationGetRelid(relation)
Definition: rel.h:456
List * fk_attrs
Definition: parsenodes.h:2189
char fk_upd_action
Definition: parsenodes.h:2192
#define RelationGetNamespace(relation)
Definition: rel.h:497

◆ AlterIndexNamespaces()

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

Definition at line 15203 of file tablecmds.c.

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

Referenced by AlterTableNamespaceInternal().

15205 {
15206  List *indexList;
15207  ListCell *l;
15208 
15209  indexList = RelationGetIndexList(rel);
15210 
15211  foreach(l, indexList)
15212  {
15213  Oid indexOid = lfirst_oid(l);
15214  ObjectAddress thisobj;
15215 
15216  thisobj.classId = RelationRelationId;
15217  thisobj.objectId = indexOid;
15218  thisobj.objectSubId = 0;
15219 
15220  /*
15221  * Note: currently, the index will not have its own dependency on the
15222  * namespace, so we don't need to do changeDependencyFor(). There's no
15223  * row type in pg_type, either.
15224  *
15225  * XXX this objsMoved test may be pointless -- surely we have a single
15226  * dependency link from a relation to each index?
15227  */
15228  if (!object_address_present(&thisobj, objsMoved))
15229  {
15230  AlterRelationNamespaceInternal(classRel, indexOid,
15231  oldNspOid, newNspOid,
15232  false, objsMoved);
15233  add_exact_object_address(&thisobj, objsMoved);
15234  }
15235  }
15236 
15237  list_free(indexList);
15238 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2527
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2467
unsigned int Oid
Definition: postgres_ext.h:31
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15133
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4514
void list_free(List *list)
Definition: list.c:1376
Definition: pg_list.h:50
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ AlterRelationNamespaceInternal()

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

Definition at line 15133 of file tablecmds.c.

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

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

15137 {
15138  HeapTuple classTup;
15139  Form_pg_class classForm;
15140  ObjectAddress thisobj;
15141  bool already_done = false;
15142 
15143  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
15144  if (!HeapTupleIsValid(classTup))
15145  elog(ERROR, "cache lookup failed for relation %u", relOid);
15146  classForm = (Form_pg_class) GETSTRUCT(classTup);
15147 
15148  Assert(classForm->relnamespace == oldNspOid);
15149 
15150  thisobj.classId = RelationRelationId;
15151  thisobj.objectId = relOid;
15152  thisobj.objectSubId = 0;
15153 
15154  /*
15155  * If the object has already been moved, don't move it again. If it's
15156  * already in the right place, don't move it, but still fire the object
15157  * access hook.
15158  */
15159  already_done = object_address_present(&thisobj, objsMoved);
15160  if (!already_done && oldNspOid != newNspOid)
15161  {
15162  /* check for duplicate name (more friendly than unique-index failure) */
15163  if (get_relname_relid(NameStr(classForm->relname),
15164  newNspOid) != InvalidOid)
15165  ereport(ERROR,
15166  (errcode(ERRCODE_DUPLICATE_TABLE),
15167  errmsg("relation \"%s\" already exists in schema \"%s\"",
15168  NameStr(classForm->relname),
15169  get_namespace_name(newNspOid))));
15170 
15171  /* classTup is a copy, so OK to scribble on */
15172  classForm->relnamespace = newNspOid;
15173 
15174  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
15175 
15176  /* Update dependency on schema if caller said so */
15177  if (hasDependEntry &&
15178  changeDependencyFor(RelationRelationId,
15179  relOid,
15180  NamespaceRelationId,
15181  oldNspOid,
15182  newNspOid) != 1)
15183  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
15184  NameStr(classForm->relname));
15185  }
15186  if (!already_done)
15187  {
15188  add_exact_object_address(&thisobj, objsMoved);
15189 
15190  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
15191  }
15192 
15193  heap_freetuple(classTup);
15194 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2527
int errcode(int sqlerrcode)
Definition: elog.c:610
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2467
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1797
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:745
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
int errmsg(const char *fmt,...)
Definition: elog.c:824
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:388
#define elog(elevel,...)
Definition: elog.h:214
#define NameStr(name)
Definition: c.h:622

◆ AlterSeqNamespaces()

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

Definition at line 15248 of file tablecmds.c.

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

Referenced by AlterTableNamespaceInternal().

15251 {
15252  Relation depRel;
15253  SysScanDesc scan;
15254  ScanKeyData key[2];
15255  HeapTuple tup;
15256 
15257  /*
15258  * SERIAL sequences are those having an auto dependency on one of the
15259  * table's columns (we don't care *which* column, exactly).
15260  */
15261  depRel = table_open(DependRelationId, AccessShareLock);
15262 
15263  ScanKeyInit(&key[0],
15264  Anum_pg_depend_refclassid,
15265  BTEqualStrategyNumber, F_OIDEQ,
15266  ObjectIdGetDatum(RelationRelationId));
15267  ScanKeyInit(&key[1],
15268  Anum_pg_depend_refobjid,
15269  BTEqualStrategyNumber, F_OIDEQ,
15271  /* we leave refobjsubid unspecified */
15272 
15273  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
15274  NULL, 2, key);
15275 
15276  while (HeapTupleIsValid(tup = systable_getnext(scan)))
15277  {
15278  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
15279  Relation seqRel;
15280 
15281  /* skip dependencies other than auto dependencies on columns */
15282  if (depForm->refobjsubid == 0 ||
15283  depForm->classid != RelationRelationId ||
15284  depForm->objsubid != 0 ||
15285  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
15286  continue;
15287 
15288  /* Use relation_open just in case it's an index */
15289  seqRel = relation_open(depForm->objid, lockmode);
15290 
15291  /* skip non-sequence relations */
15292  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
15293  {
15294  /* No need to keep the lock */
15295  relation_close(seqRel, lockmode);
15296  continue;
15297  }
15298 
15299  /* Fix the pg_class and pg_depend entries */
15300  AlterRelationNamespaceInternal(classRel, depForm->objid,
15301  oldNspOid, newNspOid,
15302  true, objsMoved);
15303 
15304  /*
15305  * Sequences used to have entries in pg_type, but no longer do. If we
15306  * ever re-instate that, we'll need to move the pg_type entry to the
15307  * new namespace, too (using AlterTypeNamespaceInternal).
15308  */
15309  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
15310 
15311  /* Now we can close it. Keep the lock till end of transaction. */
15312  relation_close(seqRel, NoLock);
15313  }
15314 
15315  systable_endscan(scan);
15316 
15318 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:569
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define RelationGetForm(relation)
Definition: rel.h:450
#define DependReferenceIndexId
Definition: indexing.h:162
#define AccessShareLock
Definition: lockdefs.h:36
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:357
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:476
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:71
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:745
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15133
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:456
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ AlterTable()

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

Definition at line 3673 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3675 {
3676  Relation rel;
3677 
3678  /* Caller is required to provide an adequate lock. */
3679  rel = relation_open(context->relid, NoLock);
3680 
3681  CheckTableNotInUse(rel, "ALTER TABLE");
3682 
3683  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
3684 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4009
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3589
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1778

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 3747 of file tablecmds.c.

References AccessExclusiveLock, AccessShareLock, AlterTableGetRelOptionsLockLevel(), AT_AddColumn, AT_AddColumnToView, AT_AddConstraint, AT_AddConstraintRecurse, AT_AddIdentity, AT_AddIndex, AT_AddIndexConstraint, AT_AddInherit, AT_AddOf, AT_AlterColumnGenericOptions, AT_AlterColumnType, AT_AlterConstraint, AT_AttachPartition, AT_ChangeOwner, AT_CheckNotNull, AT_ClusterOn, AT_ColumnDefault, AT_CookedColumnDefault, AT_DetachPartition, AT_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_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().

3748 {
3749  /*
3750  * This only works if we read catalog tables using MVCC snapshots.
3751  */
3752  ListCell *lcmd;
3754 
3755  foreach(lcmd, cmds)
3756  {
3757  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3758  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
3759 
3760  switch (cmd->subtype)
3761  {
3762  /*
3763  * These subcommands rewrite the heap, so require full locks.
3764  */
3765  case AT_AddColumn: /* may rewrite heap, in some cases and visible
3766  * to SELECT */
3767  case AT_SetTableSpace: /* must rewrite heap */
3768  case AT_AlterColumnType: /* must rewrite heap */
3769  cmd_lockmode = AccessExclusiveLock;
3770  break;
3771 
3772  /*
3773  * These subcommands may require addition of toast tables. If
3774  * we add a toast table to a table currently being scanned, we
3775  * might miss data added to the new toast table by concurrent
3776  * insert transactions.
3777  */
3778  case AT_SetStorage: /* may add toast tables, see
3779  * ATRewriteCatalogs() */
3780  cmd_lockmode = AccessExclusiveLock;
3781  break;
3782 
3783  /*
3784  * Removing constraints can affect SELECTs that have been
3785  * optimized assuming the constraint holds true. See also
3786  * CloneFkReferenced.
3787  */
3788  case AT_DropConstraint: /* as DROP INDEX */
3789  case AT_DropNotNull: /* may change some SQL plans */
3790  cmd_lockmode = AccessExclusiveLock;
3791  break;
3792 
3793  /*
3794  * Subcommands that may be visible to concurrent SELECTs
3795  */
3796  case AT_DropColumn: /* change visible to SELECT */
3797  case AT_AddColumnToView: /* CREATE VIEW */
3798  case AT_DropOids: /* used to equiv to DropColumn */
3799  case AT_EnableAlwaysRule: /* may change SELECT rules */
3800  case AT_EnableReplicaRule: /* may change SELECT rules */
3801  case AT_EnableRule: /* may change SELECT rules */
3802  case AT_DisableRule: /* may change SELECT rules */
3803  cmd_lockmode = AccessExclusiveLock;
3804  break;
3805 
3806  /*
3807  * Changing owner may remove implicit SELECT privileges
3808  */
3809  case AT_ChangeOwner: /* change visible to SELECT */
3810  cmd_lockmode = AccessExclusiveLock;
3811  break;
3812 
3813  /*
3814  * Changing foreign table options may affect optimization.
3815  */
3816  case AT_GenericOptions:
3818  cmd_lockmode = AccessExclusiveLock;
3819  break;
3820 
3821  /*
3822  * These subcommands affect write operations only.
3823  */
3824  case AT_EnableTrig:
3825  case AT_EnableAlwaysTrig:
3826  case AT_EnableReplicaTrig:
3827  case AT_EnableTrigAll:
3828  case AT_EnableTrigUser:
3829  case AT_DisableTrig:
3830  case AT_DisableTrigAll:
3831  case AT_DisableTrigUser:
3832  cmd_lockmode = ShareRowExclusiveLock;
3833  break;
3834 
3835  /*
3836  * These subcommands affect write operations only. XXX
3837  * Theoretically, these could be ShareRowExclusiveLock.
3838  */
3839  case AT_ColumnDefault:
3841  case AT_AlterConstraint:
3842  case AT_AddIndex: /* from ADD CONSTRAINT */
3843  case AT_AddIndexConstraint:
3844  case AT_ReplicaIdentity:
3845  case AT_SetNotNull:
3846  case AT_EnableRowSecurity:
3847  case AT_DisableRowSecurity:
3848  case AT_ForceRowSecurity:
3849  case AT_NoForceRowSecurity:
3850  case AT_AddIdentity:
3851  case AT_DropIdentity:
3852  case AT_SetIdentity:
3853  case AT_DropExpression:
3854  cmd_lockmode = AccessExclusiveLock;
3855  break;
3856 
3857  case AT_AddConstraint:
3858  case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
3859  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
3860  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
3861  if (IsA(cmd->def, Constraint))
3862  {
3863  Constraint *con = (Constraint *) cmd->def;
3864 
3865  switch (con->contype)
3866  {
3867  case CONSTR_EXCLUSION:
3868  case CONSTR_PRIMARY:
3869  case CONSTR_UNIQUE:
3870 
3871  /*
3872  * Cases essentially the same as CREATE INDEX. We
3873  * could reduce the lock strength to ShareLock if
3874  * we can work out how to allow concurrent catalog
3875  * updates. XXX Might be set down to
3876  * ShareRowExclusiveLock but requires further
3877  * analysis.
3878  */
3879  cmd_lockmode = AccessExclusiveLock;
3880  break;
3881  case CONSTR_FOREIGN:
3882 
3883  /*
3884  * We add triggers to both tables when we add a
3885  * Foreign Key, so the lock level must be at least
3886  * as strong as CREATE TRIGGER.
3887  */
3888  cmd_lockmode = ShareRowExclusiveLock;
3889  break;
3890 
3891  default:
3892  cmd_lockmode = AccessExclusiveLock;
3893  }
3894  }
3895  break;
3896 
3897  /*
3898  * These subcommands affect inheritance behaviour. Queries
3899  * started before us will continue to see the old inheritance
3900  * behaviour, while queries started after we commit will see
3901  * new behaviour. No need to prevent reads or writes to the
3902  * subtable while we hook it up though. Changing the TupDesc
3903  * may be a problem, so keep highest lock.
3904  */
3905  case AT_AddInherit:
3906  case AT_DropInherit:
3907  cmd_lockmode = AccessExclusiveLock;
3908  break;
3909 
3910  /*
3911  * These subcommands affect implicit row type conversion. They
3912  * have affects similar to CREATE/DROP CAST on queries. don't
3913  * provide for invalidating parse trees as a result of such
3914  * changes, so we keep these at AccessExclusiveLock.
3915  */
3916  case AT_AddOf:
3917  case AT_DropOf:
3918  cmd_lockmode = AccessExclusiveLock;
3919  break;
3920 
3921  /*
3922  * Only used by CREATE OR REPLACE VIEW which must conflict
3923  * with an SELECTs currently using the view.
3924  */
3925  case AT_ReplaceRelOptions:
3926  cmd_lockmode = AccessExclusiveLock;
3927  break;
3928 
3929  /*
3930  * These subcommands affect general strategies for performance
3931  * and maintenance, though don't change the semantic results
3932  * from normal data reads and writes. Delaying an ALTER TABLE
3933  * behind currently active writes only delays the point where
3934  * the new strategy begins to take effect, so there is no
3935  * benefit in waiting. In this case the minimum restriction
3936  * applies: we don't currently allow concurrent catalog
3937  * updates.
3938  */
3939  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
3940  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
3941  case AT_DropCluster: /* Uses MVCC in getIndexes() */
3942  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
3943  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
3944  cmd_lockmode = ShareUpdateExclusiveLock;
3945  break;
3946 
3947  case AT_SetLogged:
3948  case AT_SetUnLogged:
3949  cmd_lockmode = AccessExclusiveLock;
3950  break;
3951 
3952  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
3953  cmd_lockmode = ShareUpdateExclusiveLock;
3954  break;
3955 
3956  /*
3957  * Rel options are more complex than first appears. Options
3958  * are set here for tables, views and indexes; for historical
3959  * reasons these can all be used with ALTER TABLE, so we can't
3960  * decide between them using the basic grammar.
3961  */
3962  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
3963  * getTables() */
3964  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
3965  * getTables() */
3966  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
3967  break;
3968 
3969  case AT_AttachPartition:
3970  cmd_lockmode = ShareUpdateExclusiveLock;
3971  break;
3972 
3973  case AT_DetachPartition:
3974  cmd_lockmode = AccessExclusiveLock;
3975  break;
3976 
3977  case AT_CheckNotNull:
3978 
3979  /*
3980  * This only examines the table's schema; but lock must be
3981  * strong enough to prevent concurrent DROP NOT NULL.
3982  */
3983  cmd_lockmode = AccessShareLock;
3984  break;
3985 
3986  default: /* oops */
3987  elog(ERROR, "unrecognized alter table type: %d",
3988  (int) cmd->subtype);
3989  break;
3990  }
3991 
3992  /*
3993  * Take the greatest lockmode from any subcommand
3994  */
3995  if (cmd_lockmode > lockmode)
3996  lockmode = cmd_lockmode;
3997  }
3998 
3999  return lockmode;
4000 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
int LOCKMODE
Definition: lockdefs.h:26
#define AccessShareLock
Definition: lockdefs.h:36
AlterTableType subtype
Definition: parsenodes.h:1865
#define ERROR
Definition: elog.h:43
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define lfirst(lc)
Definition: pg_list.h:169
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:2085
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define elog(elevel,...)
Definition: elog.h:214
ConstrType contype
Definition: parsenodes.h:2154
Definition: pg_list.h:50

◆ AlterTableInternal()

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

Definition at line 3702 of file tablecmds.c.

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

3703 {
3704  Relation rel;
3705  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
3706 
3707  rel = relation_open(relid, lockmode);
3708 
3710 
3711  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
3712 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4009
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:3747
void EventTriggerAlterTableRelid(Oid objectId)

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3617 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3618 {
3619  return RangeVarGetRelidExtended(stmt->relation, lockmode,
3620  stmt->missing_ok ? RVR_MISSING_OK : 0,
3622  (void *) stmt);
3623 }
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:15647
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
RangeVar * relation
Definition: parsenodes.h:1778

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 13327 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

13328 {
13329  List *relations = NIL;
13330  ListCell *l;
13331  ScanKeyData key[1];
13332  Relation rel;
13333  TableScanDesc scan;
13334  HeapTuple tuple;
13335  Oid orig_tablespaceoid;
13336  Oid new_tablespaceoid;
13337  List *role_oids = roleSpecsToIds(stmt->roles);
13338 
13339  /* Ensure we were not asked to move something we can't */
13340  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
13341  stmt->objtype != OBJECT_MATVIEW)
13342  ereport(ERROR,
13343  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13344  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
13345 
13346  /* Get the orig and new tablespace OIDs */
13347  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
13348  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
13349 
13350  /* Can't move shared relations in to or out of pg_global */
13351  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
13352  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
13353  new_tablespaceoid == GLOBALTABLESPACE_OID)
13354  ereport(ERROR,
13355  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13356  errmsg("cannot move relations in to or out of pg_global tablespace")));
13357 
13358  /*
13359  * Must have CREATE rights on the new tablespace, unless it is the
13360  * database default tablespace (which all users implicitly have CREATE
13361  * rights on).
13362  */
13363  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
13364  {
13365  AclResult aclresult;
13366 
13367  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
13368  ACL_CREATE);
13369  if (aclresult != ACLCHECK_OK)
13370  aclcheck_error(aclresult, OBJECT_TABLESPACE,
13371  get_tablespace_name(new_tablespaceoid));
13372  }
13373 
13374  /*
13375  * Now that the checks are done, check if we should set either to
13376  * InvalidOid because it is our database's default tablespace.
13377  */
13378  if (orig_tablespaceoid == MyDatabaseTableSpace)
13379  orig_tablespaceoid = InvalidOid;
13380 
13381  if (new_tablespaceoid == MyDatabaseTableSpace)
13382  new_tablespaceoid = InvalidOid;
13383 
13384  /* no-op */
13385  if (orig_tablespaceoid == new_tablespaceoid)
13386  return new_tablespaceoid;
13387 
13388  /*
13389  * Walk the list of objects in the tablespace and move them. This will
13390  * only find objects in our database, of course.
13391  */
13392  ScanKeyInit(&key[0],
13393  Anum_pg_class_reltablespace,
13394  BTEqualStrategyNumber, F_OIDEQ,
13395  ObjectIdGetDatum(orig_tablespaceoid));
13396 
13397  rel = table_open(RelationRelationId, AccessShareLock);
13398  scan = table_beginscan_catalog(rel, 1, key);
13399  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
13400  {
13401  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
13402  Oid relOid = relForm->oid;
13403 
13404  /*
13405  * Do not move objects in pg_catalog as part of this, if an admin
13406  * really wishes to do so, they can issue the individual ALTER
13407  * commands directly.
13408  *
13409  * Also, explicitly avoid any shared tables, temp tables, or TOAST
13410  * (TOAST will be moved with the main table).
13411  */
13412  if (IsCatalogNamespace(relForm->relnamespace) ||
13413  relForm->relisshared ||
13414  isAnyTempNamespace(relForm->relnamespace) ||
13415  IsToastNamespace(relForm->relnamespace))
13416  continue;
13417 
13418  /* Only move the object type requested */
13419  if ((stmt->objtype == OBJECT_TABLE &&
13420  relForm->relkind != RELKIND_RELATION &&
13421  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
13422  (stmt->objtype == OBJECT_INDEX &&
13423  relForm->relkind != RELKIND_INDEX &&
13424  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
13425  (stmt->objtype == OBJECT_MATVIEW &&
13426  relForm->relkind != RELKIND_MATVIEW))
13427  continue;
13428 
13429  /* Check if we are only moving objects owned by certain roles */
13430  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
13431  continue;
13432 
13433  /*
13434  * Handle permissions-checking here since we are locking the tables
13435  * and also to avoid doing a bunch of work only to fail part-way. Note
13436  * that permissions will also be checked by AlterTableInternal().
13437  *
13438  * Caller must be considered an owner on the table to move it.
13439  */
13440  if (!pg_class_ownercheck(relOid, GetUserId()))
13442  NameStr(relForm->relname));
13443 
13444  if (stmt->nowait &&
13446  ereport(ERROR,
13447  (errcode(ERRCODE_OBJECT_IN_USE),
13448  errmsg("aborting because lock on relation \"%s.%s\" is not available",
13449  get_namespace_name(relForm->relnamespace),
13450  NameStr(relForm->relname))));
13451  else
13453 
13454  /* Add to our list of objects to move */
13455  relations = lappend_oid(relations, relOid);
13456  }
13457 
13458  table_endscan(scan);
13460 
13461  if (relations == NIL)
13462  ereport(NOTICE,
13463  (errcode(ERRCODE_NO_DATA_FOUND),
13464  errmsg("no matching relations in tablespace \"%s\" found",
13465  orig_tablespaceoid == InvalidOid ? "(database default)" :
13466  get_tablespace_name(orig_tablespaceoid))));
13467 
13468  /* Everything is locked, loop through and move all of the relations. */
13469  foreach(l, relations)
13470  {
13471  List *cmds = NIL;
13473 
13474  cmd->subtype = AT_SetTableSpace;
13475  cmd->name = stmt->new_tablespacename;
13476 
13477  cmds = lappend(cmds, cmd);
13478 
13480  /* OID is set by AlterTableInternal */
13481  AlterTableInternal(lfirst_oid(l), cmds, false);
13483  }
13484 
13485  return new_tablespaceoid;
13486 }
#define NIL
Definition: pg_list.h:65
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:151
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1421
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4637
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:112
Oid GetUserId(void)
Definition: miscinit.c:476
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1915
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:528
int errcode(int sqlerrcode)
Definition: elog.c:610
AlterTableType subtype
Definition: parsenodes.h:1865
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:195
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
#define OidIsValid(objectId)
Definition: c.h:651
Oid MyDatabaseTableSpace
Definition: globals.c:87
void EventTriggerAlterTableStart(Node *parsetree)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1286
List * lappend(List *list, void *datum)
Definition: list.c:321
AclResult
Definition: acl.h:177
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:576
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1434
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:674
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4687
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:177
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:863
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:3702
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:824
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1467
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:622
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3194
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:171
void EventTriggerAlterTableEnd(void)

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 15023 of file tablecmds.c.

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

Referenced by ExecAlterObjectSchemaStmt().

15024 {
15025  Relation rel;
15026  Oid relid;
15027  Oid oldNspOid;
15028  Oid nspOid;
15029  RangeVar *newrv;
15030  ObjectAddresses *objsMoved;
15031  ObjectAddress myself;
15032 
15034  stmt->missing_ok ? RVR_MISSING_OK : 0,
15036  (void *) stmt);
15037 
15038  if (!OidIsValid(relid))
15039  {
15040  ereport(NOTICE,
15041  (errmsg("relation \"%s\" does not exist, skipping",
15042  stmt->relation->relname)));
15043  return InvalidObjectAddress;
15044  }
15045 
15046  rel = relation_open(relid, NoLock);
15047 
15048  oldNspOid = RelationGetNamespace(rel);
15049 
15050  /* If it's an owned sequence, disallow moving it by itself. */
15051  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
15052  {
15053  Oid tableId;
15054  int32 colId;
15055 
15056  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
15057  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
15058  ereport(ERROR,
15059  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15060  errmsg("cannot move an owned sequence into another schema"),
15061  errdetail("Sequence \"%s\" is linked to table \"%s\".",
15063  get_rel_name(tableId))));
15064  }
15065 
15066  /* Get and lock schema OID and check its permissions. */
15067  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
15068  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
15069 
15070  /* common checks on switching namespaces */
15071  CheckSetNamespace(oldNspOid, nspOid);
15072 
15073  objsMoved = new_object_addresses();
15074  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
15075  free_object_addresses(objsMoved);
15076 
15077  ObjectAddressSet(myself, RelationRelationId, relid);
15078 
15079  if (oldschema)
15080  *oldschema = oldNspOid;
15081 
15082  /* close rel, but keep lock until commit */
15083  relation_close(rel, NoLock);
15084 
15085  return myself;
15086 }
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:797
int errcode(int sqlerrcode)
Definition: elog.c:610
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2412
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2707
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:651
signed int int32
Definition: c.h:362
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:43
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15094
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:15647
int errdetail(const char *fmt,...)
Definition: elog.c:957
#define RelationGetRelationName(relation)
Definition: rel.h:490
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2966
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:534
#define ereport(elevel,...)
Definition: elog.h:144
#define NOTICE
Definition: elog.h:37
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:824
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1840
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:422
#define RelationGetNamespace(relation)
Definition: rel.h:497

◆ AlterTableNamespaceInternal()

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

Definition at line 15094 of file tablecmds.c.

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

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

15096 {
15097  Relation classRel;
15098 
15099  Assert(objsMoved != NULL);
15100 
15101  /* OK, modify the pg_class row and pg_depend entry */
15102  classRel = table_open(RelationRelationId, RowExclusiveLock);
15103 
15104  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
15105  nspOid, true, objsMoved);
15106 
15107  /* Fix the table's row type too, if it has one */
15108  if (OidIsValid(rel->rd_rel->reltype))
15109  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
15110  nspOid, false, false, objsMoved);
15111 
15112  /* Fix other dependent stuff */
15113  if (rel->rd_rel->relkind == RELKIND_RELATION ||
15114  rel->rd_rel->relkind == RELKIND_MATVIEW ||
15115  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15116  {
15117  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
15118  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
15119  objsMoved, AccessExclusiveLock);
15120  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
15121  false, objsMoved);
15122  }
15123 
15124  table_close(classRel, RowExclusiveLock);
15125 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3533
Form_pg_class rd_rel
Definition: rel.h:109
#define OidIsValid(objectId)
Definition: c.h:651
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15203
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:15248
#define RowExclusiveLock
Definition: lockdefs.h:38
#define Assert(condition)
Definition: c.h:745
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15133
#define AccessExclusiveLock
Definition: lockdefs.h:45
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:456

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

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

Referenced by ATExecAddConstraint().

8205 {
8206  List *newcons;
8207  ListCell *lcon;
8208  List *children;
8209  ListCell *child;
8211 
8212  /* At top level, permission check was done in ATPrepCmd, else do it */
8213  if (recursing)
8215 
8216  /*
8217  * Call AddRelationNewConstraints to do the work, making sure it works on
8218  * a copy of the Constraint so transformExpr can't modify the original. It
8219  * returns a list of cooked constraints.
8220  *
8221  * If the constraint ends up getting merged with a pre-existing one, it's
8222  * omitted from the returned list, which is what we want: we do not need
8223  * to do any validation work. That can only happen at child tables,
8224  * though, since we disallow merging at the top level.
8225  */
8226  newcons = AddRelationNewConstraints(rel, NIL,
8227  list_make1(copyObject(constr)),
8228  recursing | is_readd, /* allow_merge */
8229  !recursing, /* is_local */
8230  is_readd, /* is_internal */
8231  NULL); /* queryString not available
8232  * here */
8233 
8234  /* we don't expect more than one constraint here */
8235  Assert(list_length(newcons) <= 1);
8236 
8237  /* Add each to-be-validated constraint to Phase 3's queue */
8238  foreach(lcon, newcons)
8239  {
8240  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
8241 
8242  if (!ccon->skip_validation)
8243  {
8244  NewConstraint *newcon;
8245 
8246  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
8247  newcon->name = ccon->name;
8248  newcon->contype = ccon->contype;
8249  newcon->qual = ccon->expr;
8250 
8251  tab->constraints = lappend(tab->constraints, newcon);
8252  }
8253 
8254  /* Save the actually assigned name if it was defaulted */
8255  if (constr->conname == NULL)
8256  constr->conname = ccon->name;
8257 
8258  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
8259  }
8260 
8261  /* At this point we must have a locked-down name to use */
8262  Assert(constr->conname != NULL);
8263 
8264  /* Advance command counter in case same table is visited multiple times */
8266 
8267  /*
8268  * If the constraint got merged with an existing constraint, we're done.
8269  * We mustn't recurse to child tables in this case, because they've
8270  * already got the constraint, and visiting them again would lead to an
8271  * incorrect value for coninhcount.
8272  */
8273  if (newcons == NIL)
8274  return address;
8275 
8276  /*
8277  * If adding a NO INHERIT constraint, no need to find our children.
8278  */
8279  if (constr->is_no_inherit)
8280  return address;
8281 
8282  /*
8283  * Propagate to children as appropriate. Unlike most other ALTER
8284  * routines, we have to do this one level of recursion at a time; we can't
8285  * use find_all_inheritors to do it in one pass.
8286  */
8287  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8288 
8289  /*
8290  * Check if ONLY was specified with ALTER TABLE. If so, allow the
8291  * constraint creation only if there are no children currently. Error out
8292  * otherwise.
8293  */
8294  if (!recurse && children != NIL)
8295  ereport(ERROR,
8296  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8297  errmsg("constraint must be added to child tables too")));
8298 
8299  foreach(child, children)
8300  {
8301  Oid childrelid = lfirst_oid(child);
8302  Relation childrel;
8303  AlteredTableInfo *childtab;
8304 
8305  /* find_inheritance_children already got lock */
8306  childrel = table_open(childrelid, NoLock);
8307  CheckTableNotInUse(childrel, "ALTER TABLE");
8308 
8309  /* Find or create work queue entry for this table */
8310  childtab = ATGetQueueEntry(wqueue, childrel);
8311 
8312  /* Recurse to child */
8313  ATAddCheckConstraint(wqueue, childtab, childrel,
8314  constr, recurse, true, is_readd, lockmode);
8315 
8316  table_close(childrel, NoLock);
8317  }
8318 
8319  return address;
8320 }
#define NIL
Definition: pg_list.h:65
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2553
char * name
Definition: tablecmds.c:187
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Node * qual
Definition: tablecmds.c:192
int errcode(int sqlerrcode)
Definition: elog.c:610
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:8202
char * conname
Definition: parsenodes.h:2157
unsigned int Oid
Definition: postgres_ext.h:31
#define ATT_TABLE
Definition: tablecmds.c:292
List * constraints
Definition: tablecmds.c:163
#define list_make1(x1)
Definition: pg_list.h:206
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5526
bool skip_validation
Definition: heap.h:42
ConstrType contype
Definition: heap.h:37
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3589
List * lappend(List *list, void *datum)
Definition: list.c:321
ConstrType contype
Definition: tablecmds.c:188
void * palloc0(Size size)
Definition: mcxt.c:981
void CommandCounterIncrement(void)
Definition: xact.c:1021
bool is_no_inherit
Definition: parsenodes.h:2163
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:55
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:824
Oid conoid
Definition: heap.h:38
Node * expr
Definition: heap.h:41
static void ATSimplePermissions(Relation rel, int allowed_targets)
Definition: tablecmds.c:5563
#define copyObject(obj)
Definition: nodes.h:644
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:297
char * name
Definition: heap.h:39
#define RelationGetRelid(relation)
Definition: rel.h:456
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ ATAddForeignKeyConstraint()

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

Definition at line 8338 of file tablecmds.c.

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

Referenced by ATExecAddConstraint().

8341 {
8342  Relation pkrel;
8343  int16 pkattnum[INDEX_MAX_KEYS];
8344  int16 fkattnum[INDEX_MAX_KEYS];
8345  Oid pktypoid[INDEX_MAX_KEYS];
8346  Oid fktypoid[INDEX_MAX_KEYS];
8347  Oid opclasses[INDEX_MAX_KEYS];
8348  Oid pfeqoperators[INDEX_MAX_KEYS];
8349  Oid ppeqoperators[INDEX_MAX_KEYS];
8350  Oid ffeqoperators[INDEX_MAX_KEYS];
8351  int i;
8352  int numfks,
8353  numpks;
8354  Oid indexOid;
8355  bool old_check_ok;
8356  ObjectAddress address;
8357  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
8358 
8359  /*
8360  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
8361  * delete rows out from under us.
8362  */
8363  if (OidIsValid(fkconstraint->old_pktable_oid))
8364  pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
8365  else
8366  pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
8367 
8368  /*
8369  * Validity checks (permission checks wait till we have the column
8370  * numbers)
8371  */
8372  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8373  {
8374  if (!recurse)
8375  ereport(ERROR,
8376  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8377  errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
8379  RelationGetRelationName(pkrel))));
8380  if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
8381  ereport(ERROR,
8382  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8383  errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
8385  RelationGetRelationName(pkrel)),
8386  errdetail("This feature is not yet supported on partitioned tables.")));
8387  }
8388 
8389  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
8390  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
8391  ereport(ERROR,
8392  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8393  errmsg("referenced relation \"%s\" is not a table",
8394  RelationGetRelationName(pkrel))));
8395 
8396  if (!allowSystemTableMods && IsSystemRelation(pkrel))
8397  ereport(ERROR,
8398  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
8399  errmsg("permission denied: \"%s\" is a system catalog",
8400  RelationGetRelationName(pkrel))));
8401 
8402  /*
8403  * References from permanent or unlogged tables to temp tables, and from
8404  * permanent tables to unlogged tables, are disallowed because the
8405  * referenced data can vanish out from under us. References from temp
8406  * tables to any other table type are also disallowed, because other
8407  * backends might need to run the RI triggers on the perm table, but they
8408  * can't reliably see tuples in the local buffers of other backends.
8409  */
8410  switch (rel->rd_rel->relpersistence)
8411  {
8412  case RELPERSISTENCE_PERMANENT:
8413  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
8414  ereport(ERROR,
8415  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8416  errmsg("constraints on permanent tables may reference only permanent tables")));
8417  break;
8418  case RELPERSISTENCE_UNLOGGED:
8419  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT
8420  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
8421  ereport(ERROR,
8422  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8423  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
8424  break;
8425  case RELPERSISTENCE_TEMP:
8426  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
8427  ereport(ERROR,
8428  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8429  errmsg("constraints on temporary tables may reference only temporary tables")));
8430  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
8431  ereport(ERROR,
8432  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8433  errmsg("constraints on temporary tables must involve temporary tables of this session")));
8434  break;
8435  }
8436 
8437  /*
8438  * Look up the referencing attributes to make sure they exist, and record
8439  * their attnums and type OIDs.
8440  */
8441  MemSet(pkattnum, 0, sizeof(pkattnum));
8442  MemSet(fkattnum, 0, sizeof(fkattnum));
8443  MemSet(pktypoid, 0, sizeof(pktypoid));
8444  MemSet(fktypoid, 0, sizeof(fktypoid));
8445  MemSet(opclasses, 0, sizeof(opclasses));
8446  MemSet(pfeqoperators, 0, sizeof(pfeqoperators));
8447  MemSet(ppeqoperators, 0, sizeof(ppeqoperators));
8448  MemSet(ffeqoperators, 0, sizeof(ffeqoperators));
8449 
8451  fkconstraint->fk_attrs,
8452  fkattnum, fktypoid);
8453 
8454  /*
8455  * If the attribute list for the referenced table was omitted, lookup the
8456  * definition of the primary key and use it. Otherwise, validate the
8457  * supplied attribute list. In either case, discover the index OID and
8458  * index opclasses, and the attnums and type OIDs of the attributes.
8459  */
8460  if (fkconstraint->pk_attrs == NIL)
8461  {
8462  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
8463  &fkconstraint->pk_attrs,
8464  pkattnum, pktypoid,
8465  opclasses);
8466  }
8467  else
8468  {
8469  numpks = transformColumnNameList(RelationGetRelid(pkrel),
8470  fkconstraint->pk_attrs,
8471  pkattnum, pktypoid);
8472  /* Look for an index matching the column list */
8473  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
8474  opclasses);
8475  }
8476 
8477  /*
8478  * Now we can check permissions.
8479  */
8480  checkFkeyPermissions(pkrel, pkattnum, numpks);
8481 
8482  /*
8483  * Check some things for generated columns.
8484  */
8485  for (i = 0; i < numfks; i++)
8486  {
8487  char attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
8488 
8489  if (attgenerated)
8490  {
8491  /*
8492  * Check restrictions on UPDATE/DELETE actions, per SQL standard
8493  */
8494  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
8495  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
8496  fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
8497  ereport(ERROR,
8498  (errcode(ERRCODE_SYNTAX_ERROR),
8499  errmsg("invalid %s action for foreign key constraint containing generated column",
8500  "ON UPDATE")));
8501  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
8502  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
8503  ereport(ERROR,
8504  (errcode(ERRCODE_SYNTAX_ERROR),
8505  errmsg("invalid %s action for foreign key constraint containing generated column",
8506  "ON DELETE")));
8507  }
8508  }
8509 
8510  /*
8511  * Look up the equality operators to use in the constraint.
8512  *
8513  * Note that we have to be careful about the difference between the actual
8514  * PK column type and the opclass' declared input type, which might be
8515  * only binary-compatible with it. The declared opcintype is the right
8516  * thing to probe pg_amop with.
8517  */
8518  if (numfks != numpks)
8519  ereport(ERROR,
8520  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
8521  errmsg("number of referencing and referenced columns for foreign key disagree")));
8522 
8523  /*
8524  * On the strength of a previous constraint, we might avoid scanning
8525  * tables to validate this one. See below.
8526  */
8527  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
8528  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
8529 
8530  for (i = 0; i < numpks; i++)
8531  {
8532  Oid pktype = pktypoid[i];
8533  Oid fktype = fktypoid[i];
8534  Oid fktyped;
8535  HeapTuple cla_ht;
8536  Form_pg_opclass cla_tup;
8537  Oid amid;
8538  Oid opfamily;
8539  Oid opcintype;
8540  Oid pfeqop;
8541  Oid ppeqop;
8542  Oid ffeqop;
8543  int16 eqstrategy;
8544  Oid pfeqop_right;
8545 
8546  /* We need several fields out of the pg_opclass entry */
8547  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
8548  if (!HeapTupleIsValid(cla_ht))
8549  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
8550  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
8551  amid = cla_tup->opcmethod;
8552  opfamily = cla_tup->opcfamily;
8553  opcintype = cla_tup->opcintype;
8554  ReleaseSysCache(cla_ht);
8555 
8556  /*
8557  * Check it's a btree; currently this can never fail since no other
8558  * index AMs support unique indexes. If we ever did have other types
8559  * of unique indexes, we'd need a way to determine which operator
8560  * strategy number is equality. (Is it reasonable to insist that
8561  * every such index AM use btree's number for equality?)
8562  */
8563  if (amid != BTREE_AM_OID)
8564  elog(ERROR, "only b-tree indexes are supported for foreign keys");
8565  eqstrategy = BTEqualStrategyNumber;
8566 
8567  /*
8568  * There had better be a primary equality operator for the index.
8569  * We'll use it for PK = PK comparisons.
8570  */
8571  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
8572  eqstrategy);
8573 
8574  if (!OidIsValid(ppeqop))
8575  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
8576  eqstrategy, opcintype, opcintype, opfamily);
8577 
8578  /*
8579  * Are there equality operators that take exactly the FK type? Assume
8580  * we should look through any domain here.
8581  */
8582  fktyped = getBaseType(fktype);
8583 
8584  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
8585  eqstrategy);
8586  if (OidIsValid(pfeqop))
8587  {
8588  pfeqop_right = fktyped;
8589  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
8590  eqstrategy);
8591  }
8592  else
8593  {
8594  /* keep compiler quiet */
8595  pfeqop_right = InvalidOid;
8596  ffeqop = InvalidOid;
8597  }
8598 
8599  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
8600  {
8601  /*
8602  * Otherwise, look for an implicit cast from the FK type to the
8603  * opcintype, and if found, use the primary equality operator.
8604  * This is a bit tricky because opcintype might be a polymorphic
8605  * type such as ANYARRAY or ANYENUM; so what we have to test is
8606  * whether the two actual column types can be concurrently cast to
8607  * that type. (Otherwise, we'd fail to reject combinations such
8608  * as int[] and point[].)
8609  */
8610  Oid input_typeids[2];
8611  Oid target_typeids[2];
8612 
8613  input_typeids[0] = pktype;
8614  input_typeids[1] = fktype;
8615  target_typeids[0] = opcintype;
8616  target_typeids[1] = opcintype;
8617  if (can_coerce_type(2, input_typeids, target_typeids,
8619  {
8620  pfeqop = ffeqop = ppeqop;
8621  pfeqop_right = opcintype;
8622  }
8623  }
8624 
8625  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
8626  ereport(ERROR,
8627  (errcode(ERRCODE_DATATYPE_MISMATCH),
8628  errmsg("foreign key constraint \"%s\" cannot be implemented",
8629  fkconstraint->conname),
8630  errdetail("Key columns \"%s\" and \"%s\" "
8631  "are of incompatible types: %s and %s.",
8632  strVal(list_nth(fkconstraint->fk_attrs, i)),
8633  strVal(list_nth(fkconstraint->pk_attrs, i)),
8634  format_type_be(fktype),
8635  format_type_be(pktype))));
8636 
8637  if (old_check_ok)
8638  {
8639  /*
8640  * When a pfeqop changes, revalidate the constraint. We could
8641  * permit intra-opfamily changes, but that adds subtle complexity
8642  * without any concrete benefit for core types. We need not
8643  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
8644  */
8645  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
8646  old_pfeqop_item = lnext(fkconstraint->old_conpfeqop,
8647  old_pfeqop_item);
8648  }
8649  if (old_check_ok)
8650  {
8651  Oid old_fktype;
8652  Oid new_fktype;
8653  CoercionPathType old_pathtype;
8654  CoercionPathType new_pathtype;
8655  Oid old_castfunc;
8656  Oid new_castfunc;
8658  fkattnum[i] - 1);
8659 
8660  /*
8661  * Identify coercion pathways from each of the old and new FK-side
8662  * column types to the right (foreign) operand type of the pfeqop.
8663  * We may assume that pg_constraint.conkey is not changing.
8664  */
8665  old_fktype = attr->atttypid;
8666  new_fktype = fktype;
8667  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
8668  &old_castfunc);
8669  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
8670  &new_castfunc);
8671 
8672  /*
8673  * Upon a change to the cast from the FK column to its pfeqop
8674  * operand, revalidate the constraint. For this evaluation, a
8675  * binary coercion cast is equivalent to no cast at all. While
8676  * type implementors should design implicit casts with an eye
8677  * toward consistency of operations like equality, we cannot
8678  * assume here that they have done so.
8679  *
8680  * A function with a polymorphic argument could change behavior
8681  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
8682  * when the cast destination is polymorphic, we only avoid
8683  * revalidation if the input type has not changed at all. Given
8684  * just the core data types and operator classes, this requirement
8685  * prevents no would-be optimizations.
8686  *
8687  * If the cast converts from a base type to a domain thereon, then
8688  * that domain type must be the opcintype of the unique index.
8689  * Necessarily, the primary key column must then be of the domain
8690  * type. Since the constraint was previously valid, all values on
8691  * the foreign side necessarily exist on the primary side and in
8692  * turn conform to the domain. Consequently, we need not treat
8693  * domains specially here.
8694  *
8695  * Since we require that all collations share the same notion of
8696  * equality (which they do, because texteq reduces to bitwise
8697  * equality), we don't compare collation here.
8698  *
8699  * We need not directly consider the PK type. It's necessarily
8700  * binary coercible to the opcintype of the unique index column,
8701  * and ri_triggers.c will only deal with PK datums in terms of
8702  * that opcintype. Changing the opcintype also changes pfeqop.
8703  */
8704  old_check_ok = (new_pathtype == old_pathtype &&
8705  new_castfunc == old_castfunc &&
8706  (!IsPolymorphicType(pfeqop_right) ||
8707  new_fktype == old_fktype));
8708  }
8709 
8710  pfeqoperators[i] = pfeqop;
8711  ppeqoperators[i] = ppeqop;
8712  ffeqoperators[i] = ffeqop;
8713  }
8714 
8715  /*
8716  * Create all the constraint and trigger objects, recursing to partitions
8717  * as necessary. First handle the referenced side.
8718  */
8719  address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
8720  indexOid,
8721  InvalidOid, /* no parent constraint */
8722  numfks,
8723  pkattnum,
8724  fkattnum,
8725  pfeqoperators,
8726  ppeqoperators,
8727  ffeqoperators,
8728  old_check_ok);
8729 
8730  /* Now handle the referencing side. */
8731  addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
8732  indexOid,
8733  address.objectId,
8734  numfks,
8735  pkattnum,
8736  fkattnum,
8737  pfeqoperators,
8738  ppeqoperators,
8739  ffeqoperators,
8740  old_check_ok,
8741  lockmode);
8742 
8743  /*
8744  * Done. Close pk table, but keep lock until we've committed.
8745  */
8746  table_close(pkrel, NoLock);
8747 
8748  return address;
8749 }
signed short int16
Definition: c.h:361
#define NIL
Definition: pg_list.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
List * old_conpfeqop
Definition: parsenodes.h:2194
bool IsSystemRelation(Relation relation)
Definition: catalog.c:68
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:310
#define RelationGetDescr(relation)
Definition: rel.h:482
static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok, LOCKMODE lockmode)
Definition: tablecmds.c:8982
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
bool can_coerce_type(int nargs, const Oid *input_typeids, const Oid *target_typeids, CoercionContext ccontext)
Definition: parse_coerce.c:546
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2144
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids)
Definition: tablecmds.c:10069
bool rd_islocaltemp
Definition: rel.h:60
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:610
#define MemSet(start, val, len)
Definition: c.h:949
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
List * pk_attrs
Definition: parsenodes.h:2190
char * conname
Definition: parsenodes.h:2157
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:10381
#define OidIsValid(objectId)
Definition: c.h:651
CoercionPathType
Definition: parse_coerce.h:24
static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok)
Definition: tablecmds.c:8777
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
static void * list_nth(const List *list, int n)
Definition: pg_list.h:266
TupleDesc oldDesc
Definition: tablecmds.c:159
#define NoLock
Definition: lockdefs.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:957
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:164
#define RelationGetRelationName(relation)
Definition: rel.h:490
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
Oid old_pktable_oid
Definition: parsenodes.h:2195
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2142
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:102
bool allowSystemTableMods
Definition: globals.c:120
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2200
#define ereport(elevel,...)
Definition: elog.h:144
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
Definition: tablecmds.c:10114
char fk_del_action
Definition: parsenodes.h:2193
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:745
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:10352
#define INDEX_MAX_KEYS
static int list_length(const List *l)
Definition: pg_list.h:149
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
Definition: tablecmds.c:10211
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
int i
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
RangeVar * pktable
Definition: parsenodes.h:2188
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2409
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2143
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
bool skip_validation
Definition: parsenodes.h:2199
#define RelationGetRelid(relation)
Definition: rel.h:456
List * fk_attrs
Definition: parsenodes.h:2189
#define BTEqualStrategyNumber
Definition: stratnum.h:31
char fk_upd_action
Definition: parsenodes.h:2192
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ ATCheckPartitionsNotInUse()

static void ATCheckPartitionsNotInUse ( Relation  rel,
LOCKMODE  lockmode 
)
static

Definition at line 5726 of file tablecmds.c.

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

Referenced by ATPrepCmd().

5727 {
5728  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5729  {
5730  List *inh;
5731  ListCell *cell;
5732 
5733  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
5734  /* first element is the parent rel; must ignore it */
5735  for_each_from(cell, inh, 1)
5736  {
5737  Relation childrel;
5738 
5739  /* find_all_inheritors already got lock */
5740  childrel = table_open(lfirst_oid(cell), NoLock);
5741  CheckTableNotInUse(childrel, "ALTER TABLE");
5742  table_close(childrel, NoLock);
5743  }
5744  list_free(inh);
5745  }
5746 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Form_pg_class rd_rel
Definition: rel.h:109
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3589
#define for_each_from(cell, lst, N)
Definition: pg_list.h:381
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:165
void list_free(List *list)
Definition: list.c:1376
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:456
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ ATColumnChangeRequiresRewrite()

static bool ATColumnChangeRequiresRewrite ( Node expr,
AttrNumber  varattno 
)
static

Definition at line 11226 of file tablecmds.c.

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

Referenced by ATPrepAlterColumnType().

11227 {
11228  Assert(expr != NULL);
11229 
11230  for (;;)
11231  {
11232  /* only one varno, so no need to check that */
11233  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
11234  return false;
11235  else if (IsA(expr, RelabelType))
11236  expr = (Node *) ((RelabelType *) expr)->arg;
11237  else if (IsA(expr, CoerceToDomain))
11238  {
11239  CoerceToDomain *d = (CoerceToDomain *) expr;
11240 
11242  return true;
11243  expr = (Node *) d->arg;
11244  }
11245  else if (IsA(expr, FuncExpr))
11246  {
11247  FuncExpr *f = (FuncExpr *) expr;
11248 
11249  switch (f->funcid)
11250  {
11251  case F_TIMESTAMPTZ_TIMESTAMP:
11252  case F_TIMESTAMP_TIMESTAMPTZ:
11254  return true;
11255  else
11256  expr = linitial(f->args);
11257  break;
11258  default:
11259  return true;
11260  }
11261  }
11262  else
11263  return true;
11264  }
11265 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
List * args
Definition: primnodes.h:477
Definition: nodes.h:528
Definition: primnodes.h:181
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1347
#define linitial(l)
Definition: pg_list.h:174
Oid funcid
Definition: primnodes.h:469
#define Assert(condition)
Definition: c.h:745
void * arg
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:5158

◆ ATController()

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

Definition at line 4009 of file tablecmds.c.

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

Referenced by AlterTable(), and AlterTableInternal().

4012 {
4013  List *wqueue = NIL;
4014  ListCell *lcmd;
4015 
4016  /* Phase 1: preliminary examination of commands, create work queue */
4017  foreach(lcmd, cmds)
4018  {
4019  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4020 
4021  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4022  }
4023 
4024  /* Close the relation, but keep lock until commit */
4025  relation_close(rel, NoLock);
4026 
4027  /* Phase 2: update system catalogs */
4028  ATRewriteCatalogs(&wqueue, lockmode, context);
4029 
4030  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4031  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4032 }
#define NIL
Definition: pg_list.h:65
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4904
#define NoLock
Definition: lockdefs.h:34
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4044
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define lfirst(lc)
Definition: pg_list.h:169
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4373
Definition: pg_list.h:50

◆ ATDetachCheckNoForeignKeyRefs()

static void ATDetachCheckNoForeignKeyRefs ( Relation  partition)
static

Definition at line 17535 of file tablecmds.c.

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

Referenced by ATExecDetachPartition().

17536 {
17537  List *constraints;
17538  ListCell *cell;
17539 
17540  constraints = GetParentedForeignKeyRefs(partition);
17541 
17542  foreach(cell, constraints)
17543  {
17544  Oid constrOid = lfirst_oid(cell);
17545  HeapTuple tuple;
17546  Form_pg_constraint constrForm;
17547  Relation rel;
17548  Trigger trig;
17549 
17550  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
17551  if (!HeapTupleIsValid(tuple))
17552  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
17553  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
17554 
17555  Assert(OidIsValid(constrForm->conparentid));
17556  Assert(constrForm->confrelid == RelationGetRelid(partition));
17557 
17558  /* prevent data changes into the referencing table until commit */
17559  rel = table_open(constrForm->conrelid, ShareLock);
17560 
17561  MemSet(&trig, 0, sizeof(trig));
17562  trig.tgoid = InvalidOid;
17563  trig.tgname = NameStr(constrForm->conname);
17565  trig.tgisinternal = true;
17566  trig.tgconstrrelid = RelationGetRelid(partition);
17567  trig.tgconstrindid = constrForm->conindid;
17568  trig.tgconstraint = constrForm->oid;
17569  trig.tgdeferrable = false;
17570  trig.tginitdeferred = false;
17571  /* we needn't fill in remaining fields */
17572 
17573  RI_PartitionRemove_Check(&trig, rel, partition);
17574 
17575  ReleaseSysCache(tuple);
17576 
17577  table_close(rel, NoLock);
17578  }
17579 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static List * GetParentedForeignKeyRefs(Relation partition)
Definition: tablecmds.c:17482
Oid tgoid
Definition: reltrigger.h:25
bool tgisinternal
Definition: reltrigger.h:31
#define MemSet(start, val, len)
Definition: c.h:949
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:651
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:156
char tgenabled
Definition: reltrigger.h:30
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Oid tgconstraint
Definition: reltrigger.h:35
char * tgname
Definition: reltrigger.h:27
void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1575
bool tgdeferrable
Definition: reltrigger.h:36
bool tginitdeferred
Definition: reltrigger.h:37
#define NoLock
Definition: lockdefs.h:34
Oid tgconstrrelid
Definition: reltrigger.h:33
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define InvalidOid
Definition: postgres_ext.h:36
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:745
Oid tgconstrindid
Definition: reltrigger.h:34
#define elog(elevel,...)
Definition: elog.h:214
#define ShareLock
Definition: lockdefs.h:41
#define NameStr(name)
Definition: c.h:622
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:456
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 15524 of file tablecmds.c.

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

15526 {
15527  ListCell *cur_item;
15528 
15529  foreach(cur_item, on_commits)
15530  {
15531  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
15532 
15533  if (!isCommit && oc->creating_subid == mySubid)
15534  {
15535  /* cur_item must be removed */
15537  pfree(oc);
15538  }
15539  else
15540  {
15541  /* cur_item must be preserved */
15542  if (oc->creating_subid == mySubid)
15543  oc->creating_subid = parentSubid;
15544  if (oc->deleting_subid == mySubid)
15545  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
15546  }
15547  }
15548 }
SubTransactionId creating_subid
Definition: tablecmds.c:118
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:357
void pfree(void *pointer)
Definition: mcxt.c:1057
static List * on_commits
Definition: tablecmds.c:122
SubTransactionId deleting_subid
Definition: tablecmds.c:119
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:526

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 15492 of file tablecmds.c.

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

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

15493 {
15494  ListCell *cur_item;
15495 
15496  foreach(cur_item, on_commits)
15497  {
15498  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
15499 
15500  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
15502  {
15503  /* cur_item must be removed */
15505  pfree(oc);
15506  }
15507  else
15508  {
15509  /* cur_item must be preserved */
15512  }
15513  }
15514 }
SubTransactionId creating_subid
Definition: tablecmds.c:118
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:357
void pfree(void *pointer)
Definition: mcxt.c:1057
static List * on_commits
Definition: tablecmds.c:122
SubTransactionId deleting_subid
Definition: tablecmds.c:119
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:526

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

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

Referenced by ATExecCmd().

6040 {
6041  Oid myrelid = RelationGetRelid(rel);
6042  ColumnDef *colDef = castNode(ColumnDef, (*cmd)->def);
6043  bool if_not_exists = (*cmd)->missing_ok;
6044  Relation pgclass,
6045  attrdesc;
6046  HeapTuple reltup;
6047  FormData_pg_attribute attribute;
6048  int newattnum;
6049  char relkind;
6050  HeapTuple typeTuple;
6051  Oid typeOid;
6052  int32 typmod;
6053  Oid collOid;
6054  Form_pg_type tform;
6055  Expr *defval;
6056  List *children;
6057  ListCell *child;
6058  AlterTableCmd *childcmd;
6059  AclResult aclresult;
6060  ObjectAddress address;
6061  TupleDesc tupdesc;
6062  FormData_pg_attribute *aattr[] = {&attribute};
6063 
6064  /* At top level, permission check was done in ATPrepCmd, else do it */
6065  if (recursing)
6067 
6068  if (rel->rd_rel->relispartition && !recursing)
6069  ereport(ERROR,
6070  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6071  errmsg("cannot add column to a partition")));
6072 
6073  attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
6074 
6075  /*
6076  * Are we adding the column to a recursion child? If so, check whether to
6077  * merge with an existing definition for the column. If we do merge, we
6078  * must not recurse. Children will already have the column, and recursing
6079  * into them would mess up attinhcount.
6080  */
6081  if (colDef->inhcount > 0)
6082  {
6083  HeapTuple tuple;
6084 
6085  /* Does child already have a column by this name? */
6086  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
6087  if (HeapTupleIsValid(tuple))
6088  {
6089  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
6090  Oid ctypeId;
6091  int32 ctypmod;
6092  Oid ccollid;
6093 
6094  /* Child column must match on type, typmod, and collation */
6095  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
6096  if (ctypeId != childatt->atttypid ||
6097  ctypmod != childatt->atttypmod)
6098  ereport(ERROR,
6099  (errcode(ERRCODE_DATATYPE_MISMATCH),
6100  errmsg("child table \"%s\" has different type for column \"%s\"",
6101  RelationGetRelationName(rel), colDef->colname)));
6102  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
6103  if (ccollid != childatt->attcollation)
6104  ereport(ERROR,
6105  (errcode(ERRCODE_COLLATION_MISMATCH),
6106  errmsg("child table \"%s\" has different collation for column \"%s\"",
6107  RelationGetRelationName(rel), colDef->colname),
6108  errdetail("\"%s\" versus \"%s\"",
6109  get_collation_name(ccollid),
6110  get_collation_name(childatt->attcollation))));
6111 
6112  /* Bump the existing child att's inhcount */
6113  childatt->attinhcount++;
6114  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
6115 
6116  heap_freetuple(tuple);
6117 
6118  /* Inform the user about the merge */
6119  ereport(NOTICE,
6120  (errmsg("merging definition of column \"%s\" for child \"%s\"",
6121  colDef->colname, RelationGetRelationName(rel))));
6122 
6123  table_close(attrdesc, RowExclusiveLock);
6124  return InvalidObjectAddress;
6125  }
6126  }
6127 
6128  /* skip if the name already exists and if_not_exists is true */
6129  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
6130  {
6131  table_close(attrdesc, RowExclusiveLock);
6132  return InvalidObjectAddress;
6133  }
6134 
6135  /*
6136  * Okay, we need to add the column, so go ahead and do parse
6137  * transformation. This can result in queueing up, or even immediately
6138  * executing, subsidiary operations (such as creation of unique indexes);
6139  * so we mustn't do it until we have made the if_not_exists check.
6140  *
6141  * When recursing, the command was already transformed and we needn't do
6142  * so again. Also, if context isn't given we can't transform. (That
6143  * currently happens only for AT_AddColumnToView; we expect that view.c
6144  * passed us a ColumnDef that doesn't need work.)
6145  */
6146  if (context != NULL && !recursing)
6147  {
6148  *cmd = ATParseTransformCmd(wqueue, tab, rel, *cmd, recurse, lockmode,
6149  cur_pass, context);
6150  Assert(*cmd != NULL);
6151  colDef = castNode(ColumnDef, (*cmd)->def);
6152  }
6153 
6154  /*
6155  * Cannot add identity column if table has children, because identity does
6156  * not inherit. (Adding column and identity separately will work.)
6157  */
6158  if (colDef->identity &&
6159  recurse &&
6160  find_inheritance_children(myrelid, NoLock) != NIL)
6161  ereport(ERROR,
6162  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6163  errmsg("cannot recursively add identity column to table that has child tables")));
6164 
6165  pgclass = table_open(RelationRelationId, RowExclusiveLock);
6166 
6167  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
6168  if (!HeapTupleIsValid(reltup))
6169  elog(ERROR, "cache lookup failed for relation %u", myrelid);
6170  relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
6171 
6172  /* Determine the new attribute's number */
6173  newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
6174  if (newattnum > MaxHeapAttributeNumber)
6175  ereport(ERROR,
6176  (errcode(ERRCODE_TOO_MANY_COLUMNS),
6177  errmsg("tables can have at most %d columns",
6179 
6180  typeTuple = typenameType(NULL, colDef->typeName, &typmod);
6181  tform = (Form_pg_type) GETSTRUCT(typeTuple);
6182  typeOid = tform->oid;
6183 
6184  aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
6185  if (aclresult != ACLCHECK_OK)
6186  aclcheck_error_type(aclresult, typeOid);
6187 
6188  collOid = GetColumnDefCollation(NULL, colDef, typeOid);
6189 
6190  /* make sure datatype is legal for a column */
6191  CheckAttributeType(colDef->colname, typeOid, collOid,
6192  list_make1_oid(rel->rd_rel->reltype),
6193  0);
6194 
6195  /* construct new attribute's pg_attribute entry */
6196  attribute.attrelid = myrelid;
6197  namestrcpy(&(attribute.attname), colDef->colname);
6198  attribute.atttypid = typeOid;
6199  attribute.attstattarget = (newattnum > 0) ? -1 : 0;
6200  attribute.attlen = tform->typlen;
6201  attribute.atttypmod = typmod;
6202  attribute.attnum = newattnum;
6203  attribute.attbyval = tform->typbyval;
6204  attribute.attndims = list_length(colDef->typeName->arrayBounds);
6205  attribute.attstorage = tform->typstorage;
6206  attribute.attalign = tform->typalign;
6207  attribute.attnotnull = colDef->is_not_null;
6208  attribute.atthasdef = false;
6209  attribute.atthasmissing = false;
6210  attribute.attidentity = colDef->identity;
6211  attribute.attgenerated = colDef->generated;
6212  attribute.attisdropped = false;
6213  attribute.attislocal = colDef->is_local;
6214  attribute.attinhcount = colDef->inhcount;
6215  attribute.attcollation = collOid;
6216  /* attribute.attacl is handled by InsertPgAttributeTuples() */
6217 
6218  ReleaseSysCache(typeTuple);
6219 
6220  tupdesc = CreateTupleDesc(lengthof(aattr), (FormData_pg_attribute **) &aattr);
6221 
6222  InsertPgAttributeTuples(attrdesc, tupdesc, myrelid, NULL, NULL);
6223 
6224  table_close(attrdesc, RowExclusiveLock);
6225 
6226  /*
6227  * Update pg_class tuple as appropriate
6228  */
6229  ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
6230 
6231  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
6232 
6233  heap_freetuple(reltup);
6234 
6235  /* Post creation hook for new attribute */
6236  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
6237 
6238  table_close(pgclass, RowExclusiveLock);
6239 
6240  /* Make the attribute's catalog entry visible */
6242 
6243  /*
6244  * Store the DEFAULT, if any, in the catalogs
6245  */
6246  if (colDef->raw_default)
6247  {
6248  RawColumnDefault *rawEnt;
6249 
6250  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
6251  rawEnt->attnum = attribute.attnum;
6252  rawEnt->raw_default = copyObject(colDef->raw_default);
6253 
6254  /*
6255  * Attempt to skip a complete table rewrite by storing the specified
6256  * DEFAULT value outside of the heap. This may be disabled inside
6257  * AddRelationNewConstraints if the optimization cannot be applied.
6258  */
6259  rawEnt->missingMode = (!colDef->generated);
6260 
6261  rawEnt->generated = colDef->generated;
6262 
6263  /*
6264  * This function is intended for CREATE TABLE, so it processes a
6265  * _list_ of defaults, but we just do one.
6266  */
6268  false, true, false, NULL);
6269 
6270  /* Make the additional catalog changes visible */
6272 
6273  /*
6274  * Did the request for a missing value work? If not we'll have to do a
6275  * rewrite
6276  */
6277  if (!rawEnt->missingMode)
6279  }
6280 
6281  /*
6282  * Tell Phase 3 to fill in the default expression, if there is one.
6283  *
6284  * If there is no default, Phase 3 doesn't have to do anything, because
6285  * that effectively means that the default is NULL. The heap tuple access
6286  * routines always check for attnum > # of attributes in tuple, and return
6287  * NULL if so, so without any modification of the tuple data we will get
6288  * the effect of NULL values in the new column.
6289  *
6290  * An exception occurs when the new column is of a domain type: the domain
6291  * might have a NOT NULL constraint, or a check constraint that indirectly
6292  * rejects nulls. If there are any domain constraints then we construct
6293  * an explicit NULL default value that will be passed through
6294  * CoerceToDomain processing. (This is a tad inefficient, since it causes
6295  * rewriting the table which we really don't have to do, but the present
6296  * design of domain processing doesn't offer any simple way of checking
6297  * the constraints more directly.)
6298  *
6299  * Note: we use build_column_default, and not just the cooked default
6300  * returned by AddRelationNewConstraints, so that the right thing happens
6301  * when a datatype's default applies.
6302  *
6303  * Note: it might seem that this should happen at the end of Phase 2, so
6304  * that the effects of subsequent subcommands can be taken into account.
6305  * It's intentional that we do it now, though. The new column should be
6306  * filled according to what is said in the ADD COLUMN subcommand, so that
6307  * the effects are the same as if this subcommand had been run by itself
6308  * and the later subcommands had been issued in new ALTER TABLE commands.
6309  *
6310  * We can skip this entirely for relations without storage, since Phase 3
6311  * is certainly not going to touch them. System attributes don't have
6312  * interesting defaults, either.
6313  */
6314  if (RELKIND_HAS_STORAGE(relkind) && attribute.attnum > 0)
6315  {
6316  /*
6317  * For an identity column, we can't use build_column_default(),
6318  * because the sequence ownership isn't set yet. So do it manually.
6319  */
6320  if (colDef->identity)
6321  {
6323 
6324  nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
6325  nve->typeId = typeOid;
6326 
6327  defval = (Expr *) nve;
6328 
6329  /* must do a rewrite for identity columns */
6331  }
6332  else
6333  defval = (Expr *) build_column_default(rel, attribute.attnum);
6334 
6335  if (!defval && DomainHasConstraints(typeOid))
6336  {
6337  Oid baseTypeId;
6338  int32 baseTypeMod;
6339  Oid baseTypeColl;
6340 
6341  baseTypeMod = typmod;
6342  baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
6343  baseTypeColl = get_typcollation(baseTypeId);
6344  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
6345  defval = (Expr *) coerce_to_target_type(NULL,
6346  (Node *) defval,
6347  baseTypeId,
6348  typeOid,
6349  typmod,
6352  -1);
6353  if (defval == NULL) /* should not happen */
6354  elog(ERROR, "failed to coerce base type to domain");
6355  }
6356 
6357  if (defval)
6358  {
6360 
6361  newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
6362  newval->attnum = attribute.attnum;
6363  newval->expr = expression_planner(defval);
6364  newval->is_generated = (colDef->generated != '\0');
6365 
6366  tab->newvals = lappend(tab->newvals, newval);
6367  }
6368 
6369  if (DomainHasConstraints(typeOid))
6371 
6372  if (!TupleDescAttr(rel->rd_att, attribute.attnum - 1)->atthasmissing)
6373  {
6374  /*
6375  * If the new column is NOT NULL, and there is no missing value,
6376  * tell Phase 3 it needs to check for NULLs.
6377  */
6378  tab->verify_new_notnull |= colDef->is_not_null;
6379  }
6380  }
6381 
6382  /*
6383  * Add needed dependency entries for the new column.
6384  */
6385  add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
6386  add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
6387 
6388  /*
6389  * Propagate to children as appropriate. Unlike most other ALTER
6390  * routines, we have to do this one level of recursion at a time; we can't
6391  * use find_all_inheritors to do it in one pass.
6392  */
6393  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
6394 
6395  /*
6396  * If we are told not to recurse, there had better not be any child
6397  * tables; else the addition would put them out of step.
6398  */
6399  if (children && !recurse)
6400  ereport(ERROR,
6401  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6402  errmsg("column must be added to child tables too")));
6403 
6404  /* Children should see column as singly inherited */
6405  if (!recursing)
6406  {
6407  childcmd = copyObject(*cmd);
6408  colDef = castNode(ColumnDef, childcmd->def);
6409  colDef->inhcount = 1;
6410  colDef->is_local = false;
6411  }
6412  else
6413  childcmd = *cmd; /* no need to copy again */
6414 
6415  foreach(child, children)
6416  {
6417  Oid childrelid = lfirst_oid(child);
6418  Relation childrel;
6419  AlteredTableInfo *childtab;
6420 
6421  /* find_inheritance_children already got lock */
6422  childrel = table_open(childrelid, NoLock);
6423  CheckTableNotInUse(childrel, "ALTER TABLE");
6424 
6425  /* Find or create work queue entry for this table */
6426  childtab = ATGetQueueEntry(wqueue, childrel);
6427 
6428  /* Recurse to child; return value is ignored */
6429  ATExecAddColumn(wqueue, childtab, childrel,
6430  &childcmd, recurse, true,
6431  lockmode, cur_pass, context);
6432 
6433  table_close(childrel, NoLock);
6434  }
6435 
6436  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
6437  return address;
6438 }
#define NIL
Definition: pg_list.h:65
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2553
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2426
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:264
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
AttrNumber attnum
Definition: heap.h:29
bool is_local
Definition: parsenodes.h:651
Oid GetUserId(void)
Definition: miscinit.c:476
#define castNode(_type_, nodeptr)
Definition: nodes.h:597
void namestrcpy(Name name, const char *str)
Definition: name.c:233
char identity
Definition: parsenodes.h:657
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:78
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * get_collation_name(Oid colloid)
Definition: lsyscache.c:1033
Expr * expression_planner(Expr *expr)
Definition: planner.c:6177
Definition: nodes.h:528
int errcode(int sqlerrcode)
Definition: elog.c:610
char generated
Definition: parsenodes.h:660
bool is_not_null
Definition: parsenodes.h:652
#define lengthof(array)
Definition: c.h:675
Form_pg_class rd_rel
Definition: rel.h:109
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define ATT_TABLE
Definition: tablecmds.c:292
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3607
signed int int32
Definition: c.h:362
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:337
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1347
#define list_make1(x1)
Definition: pg_list.h:206
RangeVar * identitySequence
Definition: parsenodes.h:658
#define AT_REWRITE_DEFAULT_VAL
Definition: event_trigger.h:33
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
Definition: tablecmds.c:6498
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
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:77
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:1280
ItemPointerData t_self
Definition: htup.h:65
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:6516
bool missingMode
Definition: heap.h:31
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:957
char generated
Definition: heap.h:32
#define RelationGetRelationName(relation)
Definition: rel.h:490
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5526
Node * raw_default
Definition: heap.h:30
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
#define ACL_USAGE
Definition: parsenodes.h:82
void InsertPgAttributeTuples(Relation pg_attribute_rel, TupleDesc tupdesc, Oid new_rel_oid, Datum *attoptions, CatalogIndexState indstate)
Definition: heap.c:730
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3589
bool verify_new_notnull
Definition: tablecmds.c:166
Node * raw_default
Definition: parsenodes.h:655
List * lappend(List *list, void *datum)
Definition: list.c:321
Oid GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid)
Definition: parse_type.c:538
Node * build_column_default(Relation rel, int attrno)
void * palloc0(Size size)
Definition: mcxt.c:981
AclResult
Definition: acl.h:177
void CommandCounterIncrement(void)
Definition: xact.c:1021
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define list_make1_oid(x1)
Definition: pg_list.h:228
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:6035
TupleDesc rd_att
Definition: rel.h:110
void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, Oid *typeid_p, int32 *typmod_p)
Definition: parse_type.c:310
FormData_pg_attribute
Definition: pg_attribute.h:177
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:55
#define ereport(elevel,...)
Definition: elog.h:144
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:2933
#define NOTICE
Definition: elog.h:37
#define MaxHeapAttributeNumber
Definition: htup_details.h:47
#define makeNode(_type_)
Definition: nodes.h:576
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:745
static AlterTableCmd * ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode, int cur_pass, AlterTableUtilityContext *context)
Definition: tablecmds.c:4769
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
static int list_length(const List *l)
Definition: pg_list.h:149
bool is_generated
Definition: tablecmds.c:209
#define newval
TypeName * typeName
Definition: parsenodes.h:649
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
List * arrayBounds
Definition: parsenodes.h:216
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:824
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:6445
#define elog(elevel,...)
Definition: elog.h:214
int inhcount
Definition: parsenodes.h:650
static void ATSimplePermissions(Relation rel, int allowed_targets)
Definition: tablecmds.c:5563
char * colname
Definition: parsenodes.h:648
#define copyObject(obj)
Definition: nodes.h:644
TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs)
Definition: tupdesc.c:89
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
Definition: heap.c:581
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4675
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:297
#define RelationGetRelid(relation)
Definition: rel.h:456
#define lfirst_oid(lc)
Definition: pg_list.h:171
AttrNumber attnum
Definition: tablecmds.c:206

◆ ATExecAddConstraint()

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

Definition at line 8087 of file tablecmds.c.

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

Referenced by ATExecCmd().

8090 {
8092 
8093  Assert(IsA(newConstraint, Constraint));
8094 
8095  /*
8096  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
8097  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
8098  * switch anyway to make it easier to add more code later.
8099  */
8100  switch (newConstraint->contype)
8101  {
8102  case CONSTR_CHECK:
8103  address =
8104  ATAddCheckConstraint(wqueue, tab, rel,
8105  newConstraint, recurse, false, is_readd,
8106  lockmode);
8107  break;
8108 
8109  case CONSTR_FOREIGN:
8110 
8111  /*
8112  * Assign or validate constraint name
8113  */
8114  if (newConstraint->conname)
8115  {
8117  RelationGetRelid(rel),
8118  newConstraint->conname))
8119  ereport(ERROR,
8121  errmsg("constraint \"%s\" for relation \"%s\" already exists",
8122  newConstraint->conname,
8123  RelationGetRelationName(rel))));
8124  }
8125  else
8126  newConstraint->conname =
8129  "fkey",
8130  RelationGetNamespace(rel),
8131  NIL);
8132 
8133  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
8134  newConstraint, InvalidOid,
8135  recurse, false,
8136  lockmode);
8137  break;
8138 
8139  default:
8140  elog(ERROR, "unrecognized constraint type: %d",
8141  (int) newConstraint->contype);
8142  }
8143 
8144  return address;
8145 }
#define NIL
Definition: pg_list.h:65
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8160
int errcode(int sqlerrcode)
Definition: elog.c:610
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:8202
char * conname
Definition: parsenodes.h:2157
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:490
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:745
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, Oid parentConstr, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:8338
ConstrType contype
Definition: parsenodes.h:2154
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
#define RelationGetRelid(relation)
Definition: rel.h:456
List * fk_attrs
Definition: parsenodes.h:2189
#define RelationGetNamespace(relation)
Definition: rel.h:497

◆ ATExecAddIdentity()

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

Definition at line 7015 of file tablecmds.c.

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

7017 {
7018  Relation attrelation;
7019  HeapTuple tuple;
7020  Form_pg_attribute attTup;
7022  ObjectAddress address;
7023  ColumnDef *cdef = castNode(ColumnDef, def);
7024 
7025  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7026 
7027  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7028  if (!HeapTupleIsValid(tuple))
7029  ereport(ERROR,
7030  (errcode(ERRCODE_UNDEFINED_COLUMN),
7031  errmsg("column \"%s\" of relation \"%s\" does not exist",
7032  colName, RelationGetRelationName(rel))));
7033  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7034  attnum = attTup->attnum;
7035 
7036  /* Can't alter a system attribute */
7037  if (attnum <= 0)
7038  ereport(ERROR,
7039  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7040  errmsg("cannot alter system column \"%s\"",
7041  colName)));
7042 
7043  /*
7044  * Creating a column as identity implies NOT NULL, so adding the identity
7045  * to an existing column that is not NOT NULL would create a state that
7046  * cannot be reproduced without contortions.
7047  */
7048  if (!attTup->attnotnull)
7049  ereport(ERROR,
7050  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7051  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
7052  colName, RelationGetRelationName(rel))));
7053 
7054  if (attTup->attidentity)
7055  ereport(ERROR,
7056  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7057  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
7058  colName, RelationGetRelationName(rel))));
7059 
7060  if (attTup->atthasdef)
7061  ereport(ERROR,
7062  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7063  errmsg("column \"%s\" of relation \"%s\" already has a default value",
7064  colName, RelationGetRelationName(rel))));
7065 
7066  attTup->attidentity = cdef->identity;
7067  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7068 
7069  InvokeObjectPostAlterHook(RelationRelationId,
7070  RelationGetRelid(rel),
7071  attTup->attnum);
7072  ObjectAddressSubSet(address, RelationRelationId,
7073  RelationGetRelid(rel), attnum);
7074  heap_freetuple(tuple);
7075 
7076  table_close(attrelation, RowExclusiveLock);
7077 
7078  return address;
7079 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define castNode(_type_, nodeptr)
Definition: nodes.h:597
char identity
Definition: parsenodes.h:657
int errcode(int sqlerrcode)
Definition: elog.c:610
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:1280
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:490
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
int16 attnum
Definition: pg_attribute.h:79
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
int errmsg(const char *fmt,...)
Definition: elog.c:824
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:456

◆ ATExecAddIndex()

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

Definition at line 7935 of file tablecmds.c.

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

Referenced by ATExecCmd().

7937 {
7938  bool check_rights;
7939  bool skip_build;
7940  bool quiet;
7941  ObjectAddress address;
7942 
7943  Assert(IsA(stmt, IndexStmt));
7944  Assert(!stmt->concurrent);
7945 
7946  /* The IndexStmt has already been through transformIndexStmt */
7947  Assert(stmt->transformed);
7948 
7949  /* suppress schema rights check when rebuilding existing index */
7950  check_rights = !is_rebuild;
7951  /* skip index build if phase 3 will do it or we're reusing an old one */
7952  skip_build = tab->rewrite > 0 || OidIsValid(stmt->oldNode);
7953  /* suppress notices when rebuilding existing index */
7954  quiet = is_rebuild;
7955 
7956  address = DefineIndex(RelationGetRelid(rel),
7957  stmt,
7958  InvalidOid, /* no predefined OID */
7959  InvalidOid, /* no parent index */
7960  InvalidOid, /* no parent constraint */
7961  true, /* is_alter_table */
7962  check_rights,
7963  false, /* check_not_in_use - we did it already */
7964  skip_build,
7965  quiet);
7966 
7967  /*
7968  * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
7969  * index instead of building from scratch. Restore associated fields.
7970  * This may store InvalidSubTransactionId in both fields, in which case
7971  * relcache.c will assume it can rebuild the relcache entry. Hence, do
7972  * this after the CCI that made catalog rows visible to any rebuild. The
7973  * DROP of the old edition of this index will have scheduled the storage
7974  * for deletion at commit, so cancel that pending deletion.
7975  */
7976  if (OidIsValid(stmt->oldNode))
7977  {
7978  Relation irel = index_open(address.objectId, NoLock);
7979 
7980  irel->rd_createSubid = stmt->oldCreateSubid;
7982  RelationPreserveStorage(irel->rd_node, true);
7983  index_close(irel, NoLock);
7984  }
7985 
7986  return address;
7987 }
void RelationPreserveStorage(RelFileNode rnode, bool atCommit)
Definition: storage.c:240
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
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:492
SubTransactionId oldCreateSubid
Definition: parsenodes.h:2790
#define OidIsValid(objectId)
Definition: c.h:651
#define NoLock
Definition: lockdefs.h:34
bool transformed
Definition: parsenodes.h:2798
SubTransactionId oldFirstRelfilenodeSubid
Definition: parsenodes.h:2791
SubTransactionId rd_createSubid
Definition: rel.h:102
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:105
#define InvalidOid
Definition: postgres_ext.h:36
RelFileNode rd_node
Definition: rel.h:55
#define Assert(condition)
Definition: c.h:745
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
bool concurrent
Definition: parsenodes.h:2799
#define RelationGetRelid(relation)
Definition: rel.h:456
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132

◆ ATExecAddIndexConstraint()

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

Definition at line 7995 of file tablecmds.c.

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

Referenced by ATExecCmd().

7997 {
7998  Oid index_oid = stmt->indexOid;
7999  Relation indexRel;
8000  char *indexName;
8001  IndexInfo *indexInfo;
8002  char *constraintName;
8003  char constraintType;
8004  ObjectAddress address;
8005  bits16 flags;
8006 
8007  Assert(IsA(stmt, IndexStmt));
8008  Assert(OidIsValid(index_oid));
8009  Assert(stmt->isconstraint);
8010 
8011  /*
8012  * Doing this on partitioned tables is not a simple feature to implement,
8013  * so let's punt for now.
8014  */
8015  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8016  ereport(ERROR,
8017  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8018  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
8019 
8020  indexRel = index_open(index_oid, AccessShareLock);
8021 
8022  indexName = pstrdup(RelationGetRelationName(indexRel));
8023 
8024  indexInfo = BuildIndexInfo(indexRel);
8025 
8026  /* this should have been checked at parse time */
8027  if (!indexInfo->ii_Unique)
8028  elog(ERROR, "index \"%s\" is not unique", indexName);
8029 
8030  /*
8031  * Determine name to assign to constraint. We require a constraint to
8032  * have the same name as the underlying index; therefore, use the index's
8033  * existing name as the default constraint name, and if the user
8034  * explicitly gives some other name for the constraint, rename the index
8035  * to match.
8036  */
8037  constraintName = stmt->idxname;
8038  if (constraintName == NULL)
8039  constraintName = indexName;
8040  else if (strcmp(constraintName, indexName) != 0)
8041  {
8042  ereport(NOTICE,
8043  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
8044  indexName, constraintName)));
8045  RenameRelationInternal(index_oid, constraintName, false, true);
8046  }
8047 
8048  /* Extra checks needed if making primary key */
8049  if (stmt->primary)
8050  index_check_primary_key(rel, indexInfo, true, stmt);
8051 
8052  /* Note we currently don't support EXCLUSION constraints here */
8053  if (stmt->primary)
8054  constraintType = CONSTRAINT_PRIMARY;
8055  else
8056  constraintType = CONSTRAINT_UNIQUE;
8057 
8058  /* Create the catalog entries for the constraint */
8064 
8065  address = index_constraint_create(rel,
8066  index_oid,
8067  InvalidOid,
8068  indexInfo,
8069  constraintName,
8070  constraintType,
8071  flags,
8073  false); /* is_internal */
8074 
8075  index_close(indexRel, NoLock);
8076 
8077  return address;
8078 }
bool deferrable
Definition: parsenodes.h:2796
bool primary
Definition: parsenodes.h:2794
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
uint16 bits16
Definition: c.h:382
char * pstrdup(const char *in)
Definition: mcxt.c:1187
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:610
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2301
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:79
void index_check_primary_key(Relation heapRel, IndexInfo *indexInfo, bool is_alter_table, IndexStmt *stmt)
Definition: index.c:201
Form_pg_class rd_rel
Definition: rel.h:109
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:651
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:77
Oid indexOid
Definition: parsenodes.h:2788
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:490
char * idxname
Definition: parsenodes.h:2777
bool allowSystemTableMods
Definition: globals.c:120
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define NOTICE
Definition: elog.h:37
bool ii_Unique
Definition: execnodes.h:172
#define Assert(condition)
Definition: c.h:745
bool initdeferred
Definition: parsenodes.h:2797
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:78
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
bool isconstraint
Definition: parsenodes.h:2795
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3487
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:76
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition: index.h:75
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:1795

◆ ATExecAddInherit()

static ObjectAddress ATExecAddInherit