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/heap.h"
#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_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/pg_locale.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 recurse, bool recursing, LOCKMODE lockmode)
 
static ObjectAddress ATExecDropExpression (Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetStatistics (Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetOptions (Relation rel, const char *colName, Node *options, bool isReset, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetStorage (Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
 
static void ATPrepDropColumn (List **wqueue, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode, AlterTableUtilityContext *context)
 
static ObjectAddress ATExecDropColumn (List **wqueue, Relation rel, const char *colName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode, ObjectAddresses *addrs)
 
static ObjectAddress ATExecAddIndex (AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
 
static ObjectAddress 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)
 
static void ATExecAlterCollationRefreshVersion (Relation rel, List *coll)
 
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 151 of file tablecmds.c.

Referenced by ATRewriteCatalogs().

◆ AT_PASS_ADD_COL

#define AT_PASS_ADD_COL   4 /* ADD COLUMN */

Definition at line 144 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_ADD_CONSTR

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

Definition at line 145 of file tablecmds.c.

Referenced by ATExecCmd(), and ATPrepCmd().

◆ AT_PASS_ADD_INDEX

#define AT_PASS_ADD_INDEX   8 /* ADD indexes */

Definition at line 148 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 147 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 149 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 140 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 146 of file tablecmds.c.

Referenced by ATParseTransformCmd(), and ATPrepCmd().

◆ AT_PASS_DROP

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

Definition at line 139 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_MISC

#define AT_PASS_MISC   10 /* other stuff */

Definition at line 150 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 142 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 141 of file tablecmds.c.

Referenced by ATPostAlterTypeParse().

◆ AT_PASS_UNSET

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

Definition at line 138 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ ATT_COMPOSITE_TYPE

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 295 of file tablecmds.c.

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

◆ ATT_FOREIGN_TABLE

◆ ATT_INDEX

#define ATT_INDEX   0x0008

Definition at line 294 of file tablecmds.c.

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

◆ ATT_MATVIEW

#define ATT_MATVIEW   0x0004

Definition at line 293 of file tablecmds.c.

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

◆ ATT_PARTITIONED_INDEX

#define ATT_PARTITIONED_INDEX   0x0040

Definition at line 297 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATSimplePermissions().

◆ ATT_TABLE

◆ ATT_VIEW

#define ATT_VIEW   0x0002

Definition at line 292 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 304 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 6538 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

6539 {
6540  ObjectAddress myself,
6541  referenced;
6542 
6543  /* We know the default collation is pinned, so don't bother recording it */
6544  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
6545  {
6546  myself.classId = RelationRelationId;
6547  myself.objectId = relid;
6548  myself.objectSubId = attnum;
6549  referenced.classId = CollationRelationId;
6550  referenced.objectId = collid;
6551  referenced.objectSubId = 0;
6552  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
6553  }
6554 }
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
#define OidIsValid(objectId)
Definition: c.h:698
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 6520 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

6521 {
6522  ObjectAddress myself,
6523  referenced;
6524 
6525  myself.classId = RelationRelationId;
6526  myself.objectId = relid;
6527  myself.objectSubId = attnum;
6528  referenced.classId = TypeRelationId;
6529  referenced.objectId = typid;
6530  referenced.objectSubId = 0;
6531  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
6532 }
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
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 8815 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().

8820 {
8821  ObjectAddress address;
8822  Oid constrOid;
8823  char *conname;
8824  bool conislocal;
8825  int coninhcount;
8826  bool connoinherit;
8827 
8828  /*
8829  * Verify relkind for each referenced partition. At the top level, this
8830  * is redundant with a previous check, but we need it when recursing.
8831  */
8832  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
8833  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
8834  ereport(ERROR,
8835  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8836  errmsg("referenced relation \"%s\" is not a table",
8837  RelationGetRelationName(pkrel))));
8838 
8839  /*
8840  * Caller supplies us with a constraint name; however, it may be used in
8841  * this partition, so come up with a different one in that case.
8842  */
8844  RelationGetRelid(rel),
8845  fkconstraint->conname))
8848  "fkey",
8849  RelationGetNamespace(rel), NIL);
8850  else
8851  conname = fkconstraint->conname;
8852 
8853  if (OidIsValid(parentConstr))
8854  {
8855  conislocal = false;
8856  coninhcount = 1;
8857  connoinherit = false;
8858  }
8859  else
8860  {
8861  conislocal = true;
8862  coninhcount = 0;
8863 
8864  /*
8865  * always inherit for partitioned tables, never for legacy inheritance
8866  */
8867  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
8868  }
8869 
8870  /*
8871  * Record the FK constraint in pg_constraint.
8872  */
8873  constrOid = CreateConstraintEntry(conname,
8874  RelationGetNamespace(rel),
8875  CONSTRAINT_FOREIGN,
8876  fkconstraint->deferrable,
8877  fkconstraint->initdeferred,
8878  fkconstraint->initially_valid,
8879  parentConstr,
8880  RelationGetRelid(rel),
8881  fkattnum,
8882  numfks,
8883  numfks,
8884  InvalidOid, /* not a domain constraint */
8885  indexOid,
8886  RelationGetRelid(pkrel),
8887  pkattnum,
8888  pfeqoperators,
8889  ppeqoperators,
8890  ffeqoperators,
8891  numfks,
8892  fkconstraint->fk_upd_action,
8893  fkconstraint->fk_del_action,
8894  fkconstraint->fk_matchtype,
8895  NULL, /* no exclusion constraint */
8896  NULL, /* no check constraint */
8897  NULL,
8898  conislocal, /* islocal */
8899  coninhcount, /* inhcount */
8900  connoinherit, /* conNoInherit */
8901  false); /* is_internal */
8902 
8903  ObjectAddressSet(address, ConstraintRelationId, constrOid);
8904 
8905  /*
8906  * Mark the child constraint as part of the parent constraint; it must not
8907  * be dropped on its own. (This constraint is deleted when the partition
8908  * is detached, but a special check needs to occur that the partition
8909  * contains no referenced values.)
8910  */
8911  if (OidIsValid(parentConstr))
8912  {
8913  ObjectAddress referenced;
8914 
8915  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
8916  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
8917  }
8918 
8919  /* make new constraint visible, in case we add more */
8921 
8922  /*
8923  * If the referenced table is a plain relation, create the action triggers
8924  * that enforce the constraint.
8925  */
8926  if (pkrel->rd_rel->relkind == RELKIND_RELATION)
8927  {
8929  fkconstraint,
8930  constrOid, indexOid);
8931  }
8932 
8933  /*
8934  * If the referenced table is partitioned, recurse on ourselves to handle
8935  * each partition. We need one pg_constraint row created for each
8936  * partition in addition to the pg_constraint row for the parent table.
8937  */
8938  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8939  {
8941 
8942  for (int i = 0; i < pd->nparts; i++)
8943  {
8944  Relation partRel;
8945  AttrMap *map;
8946  AttrNumber *mapped_pkattnum;
8947  Oid partIndexId;
8948 
8949  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
8950 
8951  /*
8952  * Map the attribute numbers in the referenced side of the FK
8953  * definition to match the partition's column layout.
8954  */
8956  RelationGetDescr(pkrel));
8957  if (map)
8958  {
8959  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
8960  for (int j = 0; j < numfks; j++)
8961  mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
8962  }
8963  else
8964  mapped_pkattnum = pkattnum;
8965 
8966  /* do the deed */
8967  partIndexId = index_get_partition(partRel, indexOid);
8968  if (!OidIsValid(partIndexId))
8969  elog(ERROR, "index for %u not found in partition %s",
8970  indexOid, RelationGetRelationName(partRel));
8971  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
8972  partIndexId, constrOid, numfks,
8973  mapped_pkattnum, fkattnum,
8974  pfeqoperators, ppeqoperators, ffeqoperators,
8975  old_check_ok);
8976 
8977  /* Done -- clean up (but keep the lock) */
8978  table_close(partRel, NoLock);
8979  if (map)
8980  {
8981  pfree(mapped_pkattnum);
8982  free_attrmap(map);
8983  }
8984  }
8985  }
8986 
8987  return address;
8988 }
#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:8198
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:483
char fk_matchtype
Definition: parsenodes.h:2205
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:704
bool initdeferred
Definition: parsenodes.h:2173
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
char * conname
Definition: parsenodes.h:2171
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:698
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:8815
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:259
#define ERROR
Definition: elog.h:45
bool deferrable
Definition: parsenodes.h:2172
#define NoLock
Definition: lockdefs.h:34
PartitionDesc RelationGetPartitionDesc(Relation rel)
Definition: partdesc.c:64
#define RelationGetRelationName(relation)
Definition: rel.h:491
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:10594
void CommandCounterIncrement(void)
Definition: xact.c:1021
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2214
#define ereport(elevel,...)
Definition: elog.h:155
char fk_del_action
Definition: parsenodes.h:2207
#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:915
#define elog(elevel,...)
Definition: elog.h:228
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:457
List * fk_attrs
Definition: parsenodes.h:2203
char fk_upd_action
Definition: parsenodes.h:2206
#define RelationGetNamespace(relation)
Definition: rel.h:498

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

9025 {
9026  AssertArg(OidIsValid(parentConstr));
9027 
9028  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
9029  ereport(ERROR,
9030  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
9031  errmsg("foreign key constraints are not supported on foreign tables")));
9032 
9033  /*
9034  * If the referencing relation is a plain table, add the check triggers to
9035  * it and, if necessary, schedule it to be checked in Phase 3.
9036  *
9037  * If the relation is partitioned, drill down to do it to its partitions.
9038  */
9039  if (rel->rd_rel->relkind == RELKIND_RELATION)
9040  {
9042  RelationGetRelid(pkrel),
9043  fkconstraint,
9044  parentConstr,
9045  indexOid);
9046 
9047  /*
9048  * Tell Phase 3 to check that the constraint is satisfied by existing
9049  * rows. We can skip this during table creation, when requested
9050  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
9051  * and when we're recreating a constraint following a SET DATA TYPE
9052  * operation that did not impugn its validity.
9053  */
9054  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
9055  {
9056  NewConstraint *newcon;
9057  AlteredTableInfo *tab;
9058 
9059  tab = ATGetQueueEntry(wqueue, rel);
9060 
9061  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
9062  newcon->name = get_constraint_name(parentConstr);
9063  newcon->contype = CONSTR_FOREIGN;
9064  newcon->refrelid = RelationGetRelid(pkrel);
9065  newcon->refindid = indexOid;
9066  newcon->conid = parentConstr;
9067  newcon->qual = (Node *) fkconstraint;
9068 
9069  tab->constraints = lappend(tab->constraints, newcon);
9070  }
9071  }
9072  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
9073  {
9075 
9076  /*
9077  * Recurse to take appropriate action on each partition; either we
9078  * find an existing constraint to reparent to ours, or we create a new
9079  * one.
9080  */
9081  for (int i = 0; i < pd->nparts; i++)
9082  {
9083  Oid partitionId = pd->oids[i];
9084  Relation partition = table_open(partitionId, lockmode);
9085  List *partFKs;
9086  AttrMap *attmap;
9087  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
9088  bool attached;
9089  char *conname;
9090  Oid constrOid;
9091  ObjectAddress address,
9092  referenced;
9093  ListCell *cell;
9094 
9095  CheckTableNotInUse(partition, "ALTER TABLE");
9096 
9097  attmap = build_attrmap_by_name(RelationGetDescr(partition),
9098  RelationGetDescr(rel));
9099  for (int j = 0; j < numfks; j++)
9100  mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
9101 
9102  /* Check whether an existing constraint can be repurposed */
9103  partFKs = copyObject(RelationGetFKeyList(partition));
9104  attached = false;
9105  foreach(cell, partFKs)
9106  {
9107  ForeignKeyCacheInfo *fk;
9108 
9109  fk = lfirst_node(ForeignKeyCacheInfo, cell);
9111  partitionId,
9112  parentConstr,
9113  numfks,
9114  mapped_fkattnum,
9115  pkattnum,
9116  pfeqoperators))
9117  {
9118  attached = true;
9119  break;
9120  }
9121  }
9122  if (attached)
9123  {
9124  table_close(partition, NoLock);
9125  continue;
9126  }
9127 
9128  /*
9129  * No luck finding a good constraint to reuse; create our own.
9130  */
9132  RelationGetRelid(partition),
9133  fkconstraint->conname))
9134  conname = ChooseConstraintName(RelationGetRelationName(partition),
9136  "fkey",
9137  RelationGetNamespace(partition), NIL);
9138  else
9139  conname = fkconstraint->conname;
9140  constrOid =
9141  CreateConstraintEntry(conname,
9142  RelationGetNamespace(partition),
9143  CONSTRAINT_FOREIGN,
9144  fkconstraint->deferrable,
9145  fkconstraint->initdeferred,
9146  fkconstraint->initially_valid,
9147  parentConstr,
9148  partitionId,
9149  mapped_fkattnum,
9150  numfks,
9151  numfks,
9152  InvalidOid,
9153  indexOid,
9154  RelationGetRelid(pkrel),
9155  pkattnum,
9156  pfeqoperators,
9157  ppeqoperators,
9158  ffeqoperators,
9159  numfks,
9160  fkconstraint->fk_upd_action,
9161  fkconstraint->fk_del_action,
9162  fkconstraint->fk_matchtype,
9163  NULL,
9164  NULL,
9165  NULL,
9166  false,
9167  1,
9168  false,
9169  false);
9170 
9171  /*
9172  * Give this constraint partition-type dependencies on the parent
9173  * constraint as well as the table.
9174  */
9175  ObjectAddressSet(address, ConstraintRelationId, constrOid);
9176  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
9177  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
9178  ObjectAddressSet(referenced, RelationRelationId, partitionId);
9179  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
9180 
9181  /* Make all this visible before recursing */
9183 
9184  /* call ourselves to finalize the creation and we're done */
9185  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
9186  indexOid,
9187  constrOid,
9188  numfks,
9189  pkattnum,
9190  mapped_fkattnum,
9191  pfeqoperators,
9192  ppeqoperators,
9193  ffeqoperators,
9194  old_check_ok,
9195  lockmode);
9196 
9197  table_close(partition, NoLock);
9198  }
9199  }
9200 }
#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:10717
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
char * name
Definition: tablecmds.c:186
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:8198
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define RelationGetDescr(relation)
Definition: rel.h:483
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:9020
char fk_matchtype
Definition: parsenodes.h:2205
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:191
Definition: nodes.h:528
int errcode(int sqlerrcode)
Definition: elog.c:704
bool initdeferred
Definition: parsenodes.h:2173
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
char * conname
Definition: parsenodes.h:2171
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:698
List * constraints
Definition: tablecmds.c:162
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:9617
#define ERROR
Definition: elog.h:45
bool deferrable
Definition: parsenodes.h:2172
#define lfirst_node(type, lc)
Definition: pg_list.h:172
#define NoLock
Definition: lockdefs.h:34
PartitionDesc RelationGetPartitionDesc(Relation rel)
Definition: partdesc.c:64
#define RelationGetRelationName(relation)
Definition: rel.h:491
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5548
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3594
#define AssertArg(condition)
Definition: c.h:794
List * lappend(List *list, void *datum)
Definition: list.c:336
ConstrType contype
Definition: tablecmds.c:187
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:2214
#define ereport(elevel,...)
Definition: elog.h:155
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:174
char fk_del_action
Definition: parsenodes.h:2207
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:4417
int errmsg(const char *fmt,...)
Definition: elog.c:915
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:2213
#define RelationGetRelid(relation)
Definition: rel.h:457
List * fk_attrs
Definition: parsenodes.h:2203
char fk_upd_action
Definition: parsenodes.h:2206
#define RelationGetNamespace(relation)
Definition: rel.h:498

◆ AlterIndexNamespaces()

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

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

15250 {
15251  List *indexList;
15252  ListCell *l;
15253 
15254  indexList = RelationGetIndexList(rel);
15255 
15256  foreach(l, indexList)
15257  {
15258  Oid indexOid = lfirst_oid(l);
15259  ObjectAddress thisobj;
15260 
15261  thisobj.classId = RelationRelationId;
15262  thisobj.objectId = indexOid;
15263  thisobj.objectSubId = 0;
15264 
15265  /*
15266  * Note: currently, the index will not have its own dependency on the
15267  * namespace, so we don't need to do changeDependencyFor(). There's no
15268  * row type in pg_type, either.
15269  *
15270  * XXX this objsMoved test may be pointless -- surely we have a single
15271  * dependency link from a relation to each index?
15272  */
15273  if (!object_address_present(&thisobj, objsMoved))
15274  {
15275  AlterRelationNamespaceInternal(classRel, indexOid,
15276  oldNspOid, newNspOid,
15277  false, objsMoved);
15278  add_exact_object_address(&thisobj, objsMoved);
15279  }
15280  }
15281 
15282  list_free(indexList);
15283 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2670
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2610
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:15178
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4526
void list_free(List *list)
Definition: list.c:1391
Definition: pg_list.h:50
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ AlterRelationNamespaceInternal()

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

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

15182 {
15183  HeapTuple classTup;
15184  Form_pg_class classForm;
15185  ObjectAddress thisobj;
15186  bool already_done = false;
15187 
15188  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
15189  if (!HeapTupleIsValid(classTup))
15190  elog(ERROR, "cache lookup failed for relation %u", relOid);
15191  classForm = (Form_pg_class) GETSTRUCT(classTup);
15192 
15193  Assert(classForm->relnamespace == oldNspOid);
15194 
15195  thisobj.classId = RelationRelationId;
15196  thisobj.objectId = relOid;
15197  thisobj.objectSubId = 0;
15198 
15199  /*
15200  * If the object has already been moved, don't move it again. If it's
15201  * already in the right place, don't move it, but still fire the object
15202  * access hook.
15203  */
15204  already_done = object_address_present(&thisobj, objsMoved);
15205  if (!already_done && oldNspOid != newNspOid)
15206  {
15207  /* check for duplicate name (more friendly than unique-index failure) */
15208  if (get_relname_relid(NameStr(classForm->relname),
15209  newNspOid) != InvalidOid)
15210  ereport(ERROR,
15211  (errcode(ERRCODE_DUPLICATE_TABLE),
15212  errmsg("relation \"%s\" already exists in schema \"%s\"",
15213  NameStr(classForm->relname),
15214  get_namespace_name(newNspOid))));
15215 
15216  /* classTup is a copy, so OK to scribble on */
15217  classForm->relnamespace = newNspOid;
15218 
15219  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
15220 
15221  /* Update dependency on schema if caller said so */
15222  if (hasDependEntry &&
15223  changeDependencyFor(RelationRelationId,
15224  relOid,
15225  NamespaceRelationId,
15226  oldNspOid,
15227  newNspOid) != 1)
15228  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
15229  NameStr(classForm->relname));
15230  }
15231  if (!already_done)
15232  {
15233  add_exact_object_address(&thisobj, objsMoved);
15234 
15235  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
15236  }
15237 
15238  heap_freetuple(classTup);
15239 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2670
int errcode(int sqlerrcode)
Definition: elog.c:704
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2610
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:45
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1829
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3289
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:155
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:792
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:302
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:175
int errmsg(const char *fmt,...)
Definition: elog.c:915
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:428
#define elog(elevel,...)
Definition: elog.h:228
#define NameStr(name)
Definition: c.h:669

◆ AlterSeqNamespaces()

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

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

15296 {
15297  Relation depRel;
15298  SysScanDesc scan;
15299  ScanKeyData key[2];
15300  HeapTuple tup;
15301 
15302  /*
15303  * SERIAL sequences are those having an auto dependency on one of the
15304  * table's columns (we don't care *which* column, exactly).
15305  */
15306  depRel = table_open(DependRelationId, AccessShareLock);
15307 
15308  ScanKeyInit(&key[0],
15309  Anum_pg_depend_refclassid,
15310  BTEqualStrategyNumber, F_OIDEQ,
15311  ObjectIdGetDatum(RelationRelationId));
15312  ScanKeyInit(&key[1],
15313  Anum_pg_depend_refobjid,
15314  BTEqualStrategyNumber, F_OIDEQ,
15316  /* we leave refobjsubid unspecified */
15317 
15318  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
15319  NULL, 2, key);
15320 
15321  while (HeapTupleIsValid(tup = systable_getnext(scan)))
15322  {
15323  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
15324  Relation seqRel;
15325 
15326  /* skip dependencies other than auto dependencies on columns */
15327  if (depForm->refobjsubid == 0 ||
15328  depForm->classid != RelationRelationId ||
15329  depForm->objsubid != 0 ||
15330  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
15331  continue;
15332 
15333  /* Use relation_open just in case it's an index */
15334  seqRel = relation_open(depForm->objid, lockmode);
15335 
15336  /* skip non-sequence relations */
15337  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
15338  {
15339  /* No need to keep the lock */
15340  relation_close(seqRel, lockmode);
15341  continue;
15342  }
15343 
15344  /* Fix the pg_class and pg_depend entries */
15345  AlterRelationNamespaceInternal(classRel, depForm->objid,
15346  oldNspOid, newNspOid,
15347  true, objsMoved);
15348 
15349  /*
15350  * Sequences used to have entries in pg_type, but no longer do. If we
15351  * ever re-instate that, we'll need to move the pg_type entry to the
15352  * new namespace, too (using AlterTypeNamespaceInternal).
15353  */
15354  Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
15355 
15356  /* Now we can close it. Keep the lock till end of transaction. */
15357  relation_close(seqRel, NoLock);
15358  }
15359 
15360  systable_endscan(scan);
15361 
15363 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:593
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define RelationGetForm(relation)
Definition: rel.h:451
#define AccessShareLock
Definition: lockdefs.h:36
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:381
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:500
#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:74
#define DependReferenceIndexId
Definition: pg_depend.h:81
#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:792
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15178
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:457
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ AlterTable()

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

Definition at line 3678 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3680 {
3681  Relation rel;
3682 
3683  /* Caller is required to provide an adequate lock. */
3684  rel = relation_open(context->relid, NoLock);
3685 
3686  CheckTableNotInUse(rel, "ALTER TABLE");
3687 
3688  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode, context);
3689 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4018
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:3594
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1801

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 3752 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_AlterCollationRefreshVersion, 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().

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

◆ AlterTableInternal()

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

Definition at line 3707 of file tablecmds.c.

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

3708 {
3709  Relation rel;
3710  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
3711 
3712  rel = relation_open(relid, lockmode);
3713 
3715 
3716  ATController(NULL, rel, cmds, recurse, lockmode, NULL);
3717 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4018
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:3752
void EventTriggerAlterTableRelid(Oid objectId)

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3622 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3623 {
3624  return RangeVarGetRelidExtended(stmt->relation, lockmode,
3625  stmt->missing_ok ? RVR_MISSING_OK : 0,
3627  (void *) stmt);
3628 }
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:15692
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:236
RangeVar * relation
Definition: parsenodes.h:1801

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

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

13373 {
13374  List *relations = NIL;
13375  ListCell *l;
13376  ScanKeyData key[1];
13377  Relation rel;
13378  TableScanDesc scan;
13379  HeapTuple tuple;
13380  Oid orig_tablespaceoid;
13381  Oid new_tablespaceoid;
13382  List *role_oids = roleSpecsToIds(stmt->roles);
13383 
13384  /* Ensure we were not asked to move something we can't */
13385  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
13386  stmt->objtype != OBJECT_MATVIEW)
13387  ereport(ERROR,
13388  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13389  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
13390 
13391  /* Get the orig and new tablespace OIDs */
13392  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
13393  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
13394 
13395  /* Can't move shared relations in to or out of pg_global */
13396  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
13397  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
13398  new_tablespaceoid == GLOBALTABLESPACE_OID)
13399  ereport(ERROR,
13400  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13401  errmsg("cannot move relations in to or out of pg_global tablespace")));
13402 
13403  /*
13404  * Must have CREATE rights on the new tablespace, unless it is the
13405  * database default tablespace (which all users implicitly have CREATE
13406  * rights on).
13407  */
13408  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
13409  {
13410  AclResult aclresult;
13411 
13412  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
13413  ACL_CREATE);
13414  if (aclresult != ACLCHECK_OK)
13415  aclcheck_error(aclresult, OBJECT_TABLESPACE,
13416  get_tablespace_name(new_tablespaceoid));
13417  }
13418 
13419  /*
13420  * Now that the checks are done, check if we should set either to
13421  * InvalidOid because it is our database's default tablespace.
13422  */
13423  if (orig_tablespaceoid == MyDatabaseTableSpace)
13424  orig_tablespaceoid = InvalidOid;
13425 
13426  if (new_tablespaceoid == MyDatabaseTableSpace)
13427  new_tablespaceoid = InvalidOid;
13428 
13429  /* no-op */
13430  if (orig_tablespaceoid == new_tablespaceoid)
13431  return new_tablespaceoid;
13432 
13433  /*
13434  * Walk the list of objects in the tablespace and move them. This will
13435  * only find objects in our database, of course.
13436  */
13437  ScanKeyInit(&key[0],
13438  Anum_pg_class_reltablespace,
13439  BTEqualStrategyNumber, F_OIDEQ,
13440  ObjectIdGetDatum(orig_tablespaceoid));
13441 
13442  rel = table_open(RelationRelationId, AccessShareLock);
13443  scan = table_beginscan_catalog(rel, 1, key);
13444  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
13445  {
13446  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
13447  Oid relOid = relForm->oid;
13448 
13449  /*
13450  * Do not move objects in pg_catalog as part of this, if an admin
13451  * really wishes to do so, they can issue the individual ALTER
13452  * commands directly.
13453  *
13454  * Also, explicitly avoid any shared tables, temp tables, or TOAST
13455  * (TOAST will be moved with the main table).
13456  */
13457  if (IsCatalogNamespace(relForm->relnamespace) ||
13458  relForm->relisshared ||
13459  isAnyTempNamespace(relForm->relnamespace) ||
13460  IsToastNamespace(relForm->relnamespace))
13461  continue;
13462 
13463  /* Only move the object type requested */
13464  if ((stmt->objtype == OBJECT_TABLE &&
13465  relForm->relkind != RELKIND_RELATION &&
13466  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
13467  (stmt->objtype == OBJECT_INDEX &&
13468  relForm->relkind != RELKIND_INDEX &&
13469  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
13470  (stmt->objtype == OBJECT_MATVIEW &&
13471  relForm->relkind != RELKIND_MATVIEW))
13472  continue;
13473 
13474  /* Check if we are only moving objects owned by certain roles */
13475  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
13476  continue;
13477 
13478  /*
13479  * Handle permissions-checking here since we are locking the tables
13480  * and also to avoid doing a bunch of work only to fail part-way. Note
13481  * that permissions will also be checked by AlterTableInternal().
13482  *
13483  * Caller must be considered an owner on the table to move it.
13484  */
13485  if (!pg_class_ownercheck(relOid, GetUserId()))
13487  NameStr(relForm->relname));
13488 
13489  if (stmt->nowait &&
13491  ereport(ERROR,
13492  (errcode(ERRCODE_OBJECT_IN_USE),
13493  errmsg("aborting because lock on relation \"%s.%s\" is not available",
13494  get_namespace_name(relForm->relnamespace),
13495  NameStr(relForm->relname))));
13496  else
13498 
13499  /* Add to our list of objects to move */
13500  relations = lappend_oid(relations, relOid);
13501  }
13502 
13503  table_endscan(scan);
13505 
13506  if (relations == NIL)
13507  ereport(NOTICE,
13508  (errcode(ERRCODE_NO_DATA_FOUND),
13509  errmsg("no matching relations in tablespace \"%s\" found",
13510  orig_tablespaceoid == InvalidOid ? "(database default)" :
13511  get_tablespace_name(orig_tablespaceoid))));
13512 
13513  /* Everything is locked, loop through and move all of the relations. */
13514  foreach(l, relations)
13515  {
13516  List *cmds = NIL;
13518 
13519  cmd->subtype = AT_SetTableSpace;
13520  cmd->name = stmt->new_tablespacename;
13521 
13522  cmds = lappend(cmds, cmd);
13523 
13525  /* OID is set by AlterTableInternal */
13526  AlterTableInternal(lfirst_oid(l), cmds, false);
13528  }
13529 
13530  return new_tablespaceoid;
13531 }
#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:1433
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4640
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:1947
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:528
int errcode(int sqlerrcode)
Definition: elog.c:704
AlterTableType subtype
Definition: parsenodes.h:1889
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:193
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
#define OidIsValid(objectId)
Definition: c.h:698
Oid MyDatabaseTableSpace
Definition: globals.c:88
void EventTriggerAlterTableStart(Node *parsetree)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3297
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:45
#define ACL_CREATE
Definition: parsenodes.h:84
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3289
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1304
List * lappend(List *list, void *datum)
Definition: list.c:336
AclResult
Definition: acl.h:177
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:155
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:576
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1436
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:689
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4690
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:175
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:962
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:3707
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:915
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1479
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:669
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 15068 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().

15069 {
15070  Relation rel;
15071  Oid relid;
15072  Oid oldNspOid;
15073  Oid nspOid;
15074  RangeVar *newrv;
15075  ObjectAddresses *objsMoved;
15076  ObjectAddress myself;
15077 
15079  stmt->missing_ok ? RVR_MISSING_OK : 0,
15081  (void *) stmt);
15082 
15083  if (!OidIsValid(relid))
15084  {
15085  ereport(NOTICE,
15086  (errmsg("relation \"%s\" does not exist, skipping",
15087  stmt->relation->relname)));
15088  return InvalidObjectAddress;
15089  }
15090 
15091  rel = relation_open(relid, NoLock);
15092 
15093  oldNspOid = RelationGetNamespace(rel);
15094 
15095  /* If it's an owned sequence, disallow moving it by itself. */
15096  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
15097  {
15098  Oid tableId;
15099  int32 colId;
15100 
15101  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
15102  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
15103  ereport(ERROR,
15104  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
15105  errmsg("cannot move an owned sequence into another schema"),
15106  errdetail("Sequence \"%s\" is linked to table \"%s\".",
15108  get_rel_name(tableId))));
15109  }
15110 
15111  /* Get and lock schema OID and check its permissions. */
15112  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
15113  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
15114 
15115  /* common checks on switching namespaces */
15116  CheckSetNamespace(oldNspOid, nspOid);
15117 
15118  objsMoved = new_object_addresses();
15119  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
15120  free_object_addresses(objsMoved);
15121 
15122  ObjectAddressSet(myself, RelationRelationId, relid);
15123 
15124  if (oldschema)
15125  *oldschema = oldNspOid;
15126 
15127  /* close rel, but keep lock until commit */
15128  relation_close(rel, NoLock);
15129 
15130  return myself;
15131 }
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:837
int errcode(int sqlerrcode)
Definition: elog.c:704
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2555
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2851
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:698
signed int int32
Definition: c.h:417
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:45
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15139
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:15692
int errdetail(const char *fmt,...)
Definition: elog.c:1048
#define RelationGetRelationName(relation)
Definition: rel.h:491
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:155
#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:915
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1872
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:422
#define RelationGetNamespace(relation)
Definition: rel.h:498

◆ AlterTableNamespaceInternal()

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

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

15141 {
15142  Relation classRel;
15143 
15144  Assert(objsMoved != NULL);
15145 
15146  /* OK, modify the pg_class row and pg_depend entry */
15147  classRel = table_open(RelationRelationId, RowExclusiveLock);
15148 
15149  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
15150  nspOid, true, objsMoved);
15151 
15152  /* Fix the table's row type too, if it has one */
15153  if (OidIsValid(rel->rd_rel->reltype))
15154  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
15155  nspOid, false, false, objsMoved);
15156 
15157  /* Fix other dependent stuff */
15158  if (rel->rd_rel->relkind == RELKIND_RELATION ||
15159  rel->rd_rel->relkind == RELKIND_MATVIEW ||
15160  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
15161  {
15162  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
15163  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
15164  objsMoved, AccessExclusiveLock);
15165  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
15166  false, objsMoved);
15167  }
15168 
15169  table_close(classRel, RowExclusiveLock);
15170 }
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:3966
Form_pg_class rd_rel
Definition: rel.h:110
#define OidIsValid(objectId)
Definition: c.h:698
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15248
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:15293
#define RowExclusiveLock
Definition: lockdefs.h:38
#define Assert(condition)
Definition: c.h:792
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15178
#define AccessExclusiveLock
Definition: lockdefs.h:45
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:457

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

8243 {
8244  List *newcons;
8245  ListCell *lcon;
8246  List *children;
8247  ListCell *child;
8249 
8250  /* At top level, permission check was done in ATPrepCmd, else do it */
8251  if (recursing)
8253 
8254  /*
8255  * Call AddRelationNewConstraints to do the work, making sure it works on
8256  * a copy of the Constraint so transformExpr can't modify the original. It
8257  * returns a list of cooked constraints.
8258  *
8259  * If the constraint ends up getting merged with a pre-existing one, it's
8260  * omitted from the returned list, which is what we want: we do not need
8261  * to do any validation work. That can only happen at child tables,
8262  * though, since we disallow merging at the top level.
8263  */
8264  newcons = AddRelationNewConstraints(rel, NIL,
8265  list_make1(copyObject(constr)),
8266  recursing | is_readd, /* allow_merge */
8267  !recursing, /* is_local */
8268  is_readd, /* is_internal */
8269  NULL); /* queryString not available
8270  * here */
8271 
8272  /* we don't expect more than one constraint here */
8273  Assert(list_length(newcons) <= 1);
8274 
8275  /* Add each to-be-validated constraint to Phase 3's queue */
8276  foreach(lcon, newcons)
8277  {
8278  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
8279 
8280  if (!ccon->skip_validation)
8281  {
8282  NewConstraint *newcon;
8283 
8284  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
8285  newcon->name = ccon->name;
8286  newcon->contype = ccon->contype;
8287  newcon->qual = ccon->expr;
8288 
8289  tab->constraints = lappend(tab->constraints, newcon);
8290  }
8291 
8292  /* Save the actually assigned name if it was defaulted */
8293  if (constr->conname == NULL)
8294  constr->conname = ccon->name;
8295 
8296  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
8297  }
8298 
8299  /* At this point we must have a locked-down name to use */
8300  Assert(constr->conname != NULL);
8301 
8302  /* Advance command counter in case same table is visited multiple times */
8304 
8305  /*
8306  * If the constraint got merged with an existing constraint, we're done.
8307  * We mustn't recurse to child tables in this case, because they've
8308  * already got the constraint, and visiting them again would lead to an
8309  * incorrect value for coninhcount.
8310  */
8311  if (newcons == NIL)
8312  return address;
8313 
8314  /*
8315  * If adding a NO INHERIT constraint, no need to find our children.
8316  */
8317  if (constr->is_no_inherit)
8318  return address;
8319 
8320  /*
8321  * Propagate to children as appropriate. Unlike most other ALTER
8322  * routines, we have to do this one level of recursion at a time; we can't
8323  * use find_all_inheritors to do it in one pass.
8324  */
8325  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
8326 
8327  /*
8328  * Check if ONLY was specified with ALTER TABLE. If so, allow the
8329  * constraint creation only if there are no children currently. Error out
8330  * otherwise.
8331  */
8332  if (!recurse && children != NIL)
8333  ereport(ERROR,
8334  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
8335  errmsg("constraint must be added to child tables too")));
8336 
8337  foreach(child, children)
8338  {
8339  Oid childrelid = lfirst_oid(child);
8340  Relation childrel;
8341  AlteredTableInfo *childtab;
8342 
8343  /* find_inheritance_children already got lock */
8344  childrel = table_open(childrelid, NoLock);
8345  CheckTableNotInUse(childrel, "ALTER TABLE");
8346 
8347  /* Find or create work queue entry for this table */
8348  childtab = ATGetQueueEntry(wqueue, childrel);
8349 
8350  /* Recurse to child */
8351  ATAddCheckConstraint(wqueue, childtab, childrel,
8352  constr, recurse, true, is_readd, lockmode);
8353 
8354  table_close(childrel, NoLock);
8355  }
8356 
8357  return address;
8358 }
#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:2564
char * name
Definition: tablecmds.c:186
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Node * qual
Definition: tablecmds.c:191
int errcode(int sqlerrcode)
Definition: elog.c:704
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:8240
char * conname
Definition: parsenodes.h:2171
unsigned int Oid
Definition: postgres_ext.h:31
#define ATT_TABLE
Definition: tablecmds.c:291
List * constraints
Definition: tablecmds.c:162
#define list_make1(x1)
Definition: pg_list.h:206
#define ERROR
Definition: elog.h:45
#define NoLock
Definition: lockdefs.h:34
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5548
bool skip_validation
Definition: heap.h:42
ConstrType contype
Definition: heap.h:37
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3594
List * lappend(List *list, void *datum)
Definition: list.c:336
ConstrType contype
Definition: tablecmds.c:187
void * palloc0(Size size)
Definition: mcxt.c:981
void CommandCounterIncrement(void)
Definition: xact.c:1021
bool is_no_inherit
Definition: parsenodes.h:2177
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:55
#define ereport(elevel,...)
Definition: elog.h:155
#define Assert(condition)
Definition: c.h:792
#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:915
Oid conoid
Definition: heap.h:38
Node * expr
Definition: heap.h:41
static void ATSimplePermissions(Relation rel, int allowed_targets)
Definition: tablecmds.c:5585
#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:296
char * name
Definition: heap.h:39
#define RelationGetRelid(relation)
Definition: rel.h:457
#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 8376 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().

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

◆ ATCheckPartitionsNotInUse()

static void ATCheckPartitionsNotInUse ( Relation  rel,
LOCKMODE  lockmode 
)
static

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

5749 {
5750  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5751  {
5752  List *inh;
5753  ListCell *cell;
5754 
5755  inh = find_all_inheritors(RelationGetRelid(rel), lockmode, NULL);
5756  /* first element is the parent rel; must ignore it */
5757  for_each_from(cell, inh, 1)
5758  {
5759  Relation childrel;
5760 
5761  /* find_all_inheritors already got lock */
5762  childrel = table_open(lfirst_oid(cell), NoLock);
5763  CheckTableNotInUse(childrel, "ALTER TABLE");
5764  table_close(childrel, NoLock);
5765  }
5766  list_free(inh);
5767  }
5768 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Form_pg_class rd_rel
Definition: rel.h:110
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3594
#define for_each_from(cell, lst, N)
Definition: pg_list.h:393
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:165
void list_free(List *list)
Definition: list.c:1391
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:457
#define lfirst_oid(lc)
Definition: pg_list.h:171

◆ ATColumnChangeRequiresRewrite()

static bool ATColumnChangeRequiresRewrite ( Node expr,
AttrNumber  varattno 
)
static

Definition at line 11267 of file tablecmds.c.

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

Referenced by ATPrepAlterColumnType().

11268 {
11269  Assert(expr != NULL);
11270 
11271  for (;;)
11272  {
11273  /* only one varno, so no need to check that */
11274  if (IsA(expr, Var) && ((Var *) expr)->varattno == varattno)
11275  return false;
11276  else if (IsA(expr, RelabelType))
11277  expr = (Node *) ((RelabelType *) expr)->arg;
11278  else if (IsA(expr, CoerceToDomain))
11279  {
11280  CoerceToDomain *d = (CoerceToDomain *) expr;
11281 
11283  return true;
11284  expr = (Node *) d->arg;
11285  }
11286  else if (IsA(expr, FuncExpr))
11287  {
11288  FuncExpr *f = (FuncExpr *) expr;
11289 
11290  switch (f->funcid)
11291  {
11292  case F_TIMESTAMPTZ_TIMESTAMP:
11293  case F_TIMESTAMP_TIMESTAMPTZ:
11295  return true;
11296  else
11297  expr = linitial(f->args);
11298  break;
11299  default:
11300  return true;
11301  }
11302  }
11303  else
11304  return true;
11305  }
11306 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
List * args
Definition: primnodes.h:498
Definition: nodes.h:528
Definition: primnodes.h:181
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1391
#define linitial(l)
Definition: pg_list.h:174
Oid funcid
Definition: primnodes.h:490
#define Assert(condition)
Definition: c.h:792
void * arg
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:5169

◆ ATController()

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

Definition at line 4018 of file tablecmds.c.

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

Referenced by AlterTable(), and AlterTableInternal().

4021 {
4022  List *wqueue = NIL;
4023  ListCell *lcmd;
4024 
4025  /* Phase 1: preliminary examination of commands, create work queue */
4026  foreach(lcmd, cmds)
4027  {
4028  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
4029 
4030  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode, context);
4031  }
4032 
4033  /* Close the relation, but keep lock until commit */
4034  relation_close(rel, NoLock);
4035 
4036  /* Phase 2: update system catalogs */
4037  ATRewriteCatalogs(&wqueue, lockmode, context);
4038 
4039  /* Phase 3: scan/rewrite tables as needed, and run afterStmts */
4040  ATRewriteTables(parsetree, &wqueue, lockmode, context);
4041 }
#define NIL
Definition: pg_list.h:65
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, AlterTableUtilityContext *context)
Definition: tablecmds.c:4926
#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:4053
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:4390
Definition: pg_list.h:50

◆ ATDetachCheckNoForeignKeyRefs()

static void ATDetachCheckNoForeignKeyRefs ( Relation  partition)
static

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

17582 {
17583  List *constraints;
17584  ListCell *cell;
17585 
17586  constraints = GetParentedForeignKeyRefs(partition);
17587 
17588  foreach(cell, constraints)
17589  {
17590  Oid constrOid = lfirst_oid(cell);
17591  HeapTuple tuple;
17592  Form_pg_constraint constrForm;
17593  Relation rel;
17594  Trigger trig;
17595 
17596  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
17597  if (!HeapTupleIsValid(tuple))
17598  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
17599  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
17600 
17601  Assert(OidIsValid(constrForm->conparentid));
17602  Assert(constrForm->confrelid == RelationGetRelid(partition));
17603 
17604  /* prevent data changes into the referencing table until commit */
17605  rel = table_open(constrForm->conrelid, ShareLock);
17606 
17607  MemSet(&trig, 0, sizeof(trig));
17608  trig.tgoid = InvalidOid;
17609  trig.tgname = NameStr(constrForm->conname);
17611  trig.tgisinternal = true;
17612  trig.tgconstrrelid = RelationGetRelid(partition);
17613  trig.tgconstrindid = constrForm->conindid;
17614  trig.tgconstraint = constrForm->oid;
17615  trig.tgdeferrable = false;
17616  trig.tginitdeferred = false;
17617  /* we needn't fill in remaining fields */
17618 
17619  RI_PartitionRemove_Check(&trig, rel, partition);
17620 
17621  ReleaseSysCache(tuple);
17622 
17623  table_close(rel, NoLock);
17624  }
17625 }
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:17528
Oid tgoid
Definition: reltrigger.h:25
bool tgisinternal
Definition: reltrigger.h:31
#define MemSet(start, val, len)
Definition: c.h:996
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:698
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:148
char tgenabled
Definition: reltrigger.h:30
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:45
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:1127
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
#define InvalidOid
Definition: postgres_ext.h:36
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:792
Oid tgconstrindid
Definition: reltrigger.h:34
#define elog(elevel,...)
Definition: elog.h:228
#define ShareLock
Definition: lockdefs.h:41
#define NameStr(name)
Definition: c.h:669
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:457
#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 15569 of file tablecmds.c.

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

15571 {
15572  ListCell *cur_item;
15573 
15574  foreach(cur_item, on_commits)
15575  {
15576  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
15577 
15578  if (!isCommit && oc->creating_subid == mySubid)
15579  {
15580  /* cur_item must be removed */
15582  pfree(oc);
15583  }
15584  else
15585  {
15586  /* cur_item must be preserved */
15587  if (oc->creating_subid == mySubid)
15588  oc->creating_subid = parentSubid;
15589  if (oc->deleting_subid == mySubid)
15590  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
15591  }
15592  }
15593 }
SubTransactionId creating_subid
Definition: tablecmds.c:117
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
void pfree(void *pointer)
Definition: mcxt.c:1057
static List * on_commits
Definition: tablecmds.c:121
SubTransactionId deleting_subid
Definition: tablecmds.c:118
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:581

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 15537 of file tablecmds.c.

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

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

15538 {
15539  ListCell *cur_item;
15540 
15541  foreach(cur_item, on_commits)
15542  {
15543  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
15544 
15545  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
15547  {
15548  /* cur_item must be removed */
15550  pfree(oc);
15551  }
15552  else
15553  {
15554  /* cur_item must be preserved */
15557  }
15558  }
15559 }
SubTransactionId creating_subid
Definition: tablecmds.c:117
#define foreach_delete_current(lst, cell)
Definition: pg_list.h:369
void pfree(void *pointer)
Definition: mcxt.c:1057
static List * on_commits
Definition: tablecmds.c:121
SubTransactionId deleting_subid
Definition: tablecmds.c:118
#define lfirst(lc)
Definition: pg_list.h:169
#define InvalidSubTransactionId
Definition: c.h:581

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

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

◆ ATExecAddConstraint()

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

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

8128 {
8130 
8131  Assert(IsA(newConstraint, Constraint));
8132 
8133  /*
8134  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
8135  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
8136  * switch anyway to make it easier to add more code later.
8137  */
8138  switch (newConstraint->contype)
8139  {
8140  case CONSTR_CHECK:
8141  address =
8142  ATAddCheckConstraint(wqueue, tab, rel,
8143  newConstraint, recurse, false, is_readd,
8144  lockmode);
8145  break;
8146 
8147  case CONSTR_FOREIGN:
8148 
8149  /*
8150  * Assign or validate constraint name
8151  */
8152  if (newConstraint->conname)
8153  {
8155  RelationGetRelid(rel),
8156  newConstraint->conname))
8157  ereport(ERROR,
8159  errmsg("constraint \"%s\" for relation \"%s\" already exists",
8160  newConstraint->conname,
8161  RelationGetRelationName(rel))));
8162  }
8163  else
8164  newConstraint->conname =
8167  "fkey",
8168  RelationGetNamespace(rel),
8169  NIL);
8170 
8171  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
8172  newConstraint, InvalidOid,
8173  recurse, false,
8174  lockmode);
8175  break;
8176 
8177  default:
8178  elog(ERROR, "unrecognized constraint type: %d",
8179  (int) newConstraint->contype);
8180  }
8181 
8182  return address;
8183 }
#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:8198
int errcode(int sqlerrcode)
Definition: elog.c:704
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:8240
char * conname
Definition: parsenodes.h:2171
#define ERROR
Definition: elog.h:45
#define RelationGetRelationName(relation)
Definition: rel.h:491
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:155
#define Assert(condition)
Definition: c.h:792
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define elog(elevel,...)
Definition: elog.h:228
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, Oid parentConstr, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:8376
ConstrType contype
Definition: parsenodes.h:2168
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
#define RelationGetRelid(relation)
Definition: rel.h:457
List * fk_attrs
Definition: parsenodes.h:2203
#define RelationGetNamespace(relation)
Definition: rel.h:498

◆ ATExecAddIdentity()

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

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

7039 {
7040  Relation attrelation;
7041  HeapTuple tuple;
7042  Form_pg_attribute attTup;
7044  ObjectAddress address;
7045  ColumnDef *cdef = castNode(ColumnDef, def);
7046 
7047  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
7048 
7049  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
7050  if (!HeapTupleIsValid(tuple))
7051  ereport(ERROR,
7052  (errcode(ERRCODE_UNDEFINED_COLUMN),
7053  errmsg("column \"%s\" of relation \"%s\" does not exist",
7054  colName, RelationGetRelationName(rel))));
7055  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
7056  attnum = attTup->attnum;
7057 
7058  /* Can't alter a system attribute */
7059  if (attnum <= 0)
7060  ereport(ERROR,
7061  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7062  errmsg("cannot alter system column \"%s\"",
7063  colName)));
7064 
7065  /*
7066  * Creating a column as identity implies NOT NULL, so adding the identity
7067  * to an existing column that is not NOT NULL would create a state that
7068  * cannot be reproduced without contortions.
7069  */
7070  if (!attTup->attnotnull)
7071  ereport(ERROR,
7072  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7073  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
7074  colName, RelationGetRelationName(rel))));
7075 
7076  if (attTup->attidentity)
7077  ereport(ERROR,
7078  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7079  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
7080  colName, RelationGetRelationName(rel))));
7081 
7082  if (attTup->atthasdef)
7083  ereport(ERROR,
7084  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
7085  errmsg("column \"%s\" of relation \"%s\" already has a default value",
7086  colName, RelationGetRelationName(rel))));
7087 
7088  attTup->attidentity = cdef->identity;
7089  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7090 
7091  InvokeObjectPostAlterHook(RelationRelationId,
7092  RelationGetRelid(rel),
7093  attTup->attnum);
7094  ObjectAddressSubSet(address, RelationRelationId,
7095  RelationGetRelid(rel), attnum);
7096  heap_freetuple(tuple);
7097 
7098  table_close(attrelation, RowExclusiveLock);
7099 
7100  return address;
7101 }
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:656
int errcode(int sqlerrcode)
Definition: elog.c:704
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ERROR
Definition: elog.h:45
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:1291
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:491
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:155
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:302
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
int errmsg(const char *fmt,...)
Definition: elog.c:915
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:457

◆ ATExecAddIndex()

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

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

7975 {
7976  bool check_rights;
7977  bool skip_build;
7978  bool quiet;
7979  ObjectAddress address;
7980 
7981  Assert(IsA(stmt, IndexStmt));
7982  Assert(!stmt->concurrent);
7983 
7984  /* The IndexStmt has already been through transformIndexStmt */
7985  Assert(stmt->transformed);
7986 
7987  /* suppress schema rights check when rebuilding existing index */
7988  check_rights = !is_rebuild;
7989  /* skip index build if phase 3 will do it or we're reusing an old one */
7990  skip_build = tab->rewrite > 0 || OidIsValid(stmt->oldNode);
7991  /* suppress notices when rebuilding existing index */
7992  quiet = is_rebuild;
7993 
7994  address = DefineIndex(RelationGetRelid(rel),
7995  stmt,
7996  InvalidOid, /* no predefined OID */
7997  InvalidOid, /* no parent index */
7998  InvalidOid, /* no parent constraint */
7999  true, /* is_alter_table */
8000  check_rights,
8001  false, /* check_not_in_use - we did it already */
8002  skip_build,
8003  quiet);
8004 
8005  /*
8006  * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
8007  * index instead of building from scratch. Restore associated fields.
8008  * This may store InvalidSubTransactionId in both fields, in which case
8009  * relcache.c will assume it can rebuild the relcache entry. Hence, do
8010  * this after the CCI that made catalog rows visible to any rebuild. The
8011  * DROP of the old edition of this index will have scheduled the storage
8012  * for deletion at commit, so cancel that pending deletion.
8013  */
8014  if (OidIsValid(stmt->oldNode))
8015  {
8016  Relation irel = index_open(address.objectId, NoLock);
8017 
8018  irel->rd_createSubid = stmt->oldCreateSubid;
8020  RelationPreserveStorage(irel->rd_node, true);
8021  index_close(irel, NoLock);
8022  }
8023 
8024  return address;
8025 }
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:506
SubTransactionId oldCreateSubid
Definition: parsenodes.h:2805
#define OidIsValid(objectId)
Definition: c.h:698
#define NoLock
Definition: lockdefs.h:34
bool transformed
Definition: parsenodes.h:2813
SubTransactionId oldFirstRelfilenodeSubid
Definition: parsenodes.h:2806
SubTransactionId rd_createSubid
Definition: rel.h:103
SubTransactionId rd_firstRelfilenodeSubid
Definition: rel.h:106
#define InvalidOid
Definition: postgres_ext.h:36
RelFileNode rd_node
Definition: rel.h:55
#define Assert(condition)
Definition: c.h:792
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
bool concurrent
Definition: parsenodes.h:2814
#define RelationGetRelid(relation)
Definition: rel.h:457
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 8033 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().

8035 {
8036  Oid index_oid = stmt->indexOid;
8037  Relation indexRel;
8038  char *indexName;
8039  IndexInfo *indexInfo;
8040  char *constraintName;
8041  char constraintType;
8042  ObjectAddress address;
8043  bits16 flags;
8044 
8045  Assert(IsA(stmt, IndexStmt));
8046  Assert(OidIsValid(index_oid));
8047  Assert(stmt->isconstraint);
8048 
8049  /*
8050  * Doing this on partitioned tables is not a simple feature to implement,
8051  * so let's punt for now.
8052  */
8053  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8054  ereport(ERROR,
8055  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8056  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
8057 
8058  indexRel = index_open(index_oid, AccessShareLock);
8059 
8060  indexName = pstrdup(RelationGetRelationName(indexRel));
8061 
8062  indexInfo = BuildIndexInfo(indexRel);
8063 
8064  /* this should have been checked at parse time */
8065  if (!indexInfo->ii_Unique)
8066  elog(ERROR, "index \"%s\" is not unique", indexName);
8067 
8068  /*
8069  * Determine name to assign to constraint. We require a constraint to
8070  * have the same name as the underlying index; therefore, use the index's
8071  * existing name as the default constraint name, and if the user
8072  * explicitly gives some other name for the constraint, rename the index
8073  * to match.
8074  */
8075  constraintName = stmt->idxname;
8076  if (constraintName == NULL)
8077  constraintName = indexName;
8078  else if (strcmp(constraintName, indexName) != 0)
8079  {
8080  ereport(NOTICE,
8081  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
8082  indexName, constraintName)));
8083  RenameRelationInternal(index_oid, constraintName, false, true);
8084  }
8085 
8086  /* Extra checks needed if making primary key */
8087  if (stmt->primary)
8088  index_check_primary_key(rel, indexInfo, true, stmt);
8089 
8090  /* Note we currently don't support EXCLUSION constraints here */
8091  if (stmt->primary)
8092  constraintType = CONSTRAINT_PRIMARY;
8093  else
8094  constraintType = CONSTRAINT_UNIQUE;
8095 
8096  /* Create the catalog entries for the constraint */
8102 
8103  address = index_constraint_create(rel,
8104  index_oid,
8105  InvalidOid,
8106  indexInfo,
8107  constraintName,
8108  constraintType,
8109  flags,
8111  false); /* is_internal */
8112 
8113  index_close(indexRel, NoLock);
8114 
8115  return address;
8116 }
bool deferrable
Definition: parsenodes.h:2811
bool primary
Definition: parsenodes.h:2809
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
uint16 bits16
Definition: c.h:437
char * pstrdup(const char *in)
Definition: mcxt.c:1187
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:704
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2471
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:91
void index_check_primary_key(Relation heapRel, IndexInfo *indexInfo, bool is_alter_table, IndexStmt *stmt)
Definition: index.c:203
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:698
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:89
Oid indexOid
Definition: parsenodes.h:2803
#define ERROR
Definition: elog.h:45
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:491
char * idxname
Definition: parsenodes.h:2792
bool allowSystemTableMods
Definition: globals.c:121
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:155
#define NOTICE
Definition: elog.h:37
bool ii_Unique
Definition: execnodes.h:171
#define Assert(condition)
Definition: c.h:792
bool initdeferred
Definition: parsenodes.h:2812
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:90
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
bool isconstraint
Definition: parsenodes.h:2810
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define elog(elevel,...)
Definition: elog.h:228
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3492