PostgreSQL Source Code  git master
tablecmds.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/multixact.h"
#include "access/reloptions.h"
#include "access/relscan.h"
#include "access/sysattr.h"
#include "access/tupconvert.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_constraint_fn.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_inherits_fn.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/pg_type_fn.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/clauses.h"
#include "optimizer/planner.h"
#include "optimizer/predtest.h"
#include "optimizer/prep.h"
#include "optimizer/var.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 "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 "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/relcache.h"
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.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
 

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_COL_ATTRS   4 /* set other column attributes */
 
#define AT_PASS_ADD_COL   5 /* ADD COLUMN */
 
#define AT_PASS_ADD_INDEX   6 /* ADD indexes */
 
#define AT_PASS_ADD_CONSTR   7 /* ADD constraints, defaults */
 
#define AT_PASS_MISC   8 /* other stuff */
 
#define AT_NUM_PASSES   9
 
#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 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 (Relation rel)
 
static ListMergeAttributes (List *schema, List *supers, char relpersistence, bool is_partition, List **supOids, List **supconstr, int *supOidCount)
 
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, int16 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 (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 validateCheckConstraint (Relation rel, HeapTuple constrtup)
 
static void validateForeignKeyConstraint (char *conname, Relation rel, Relation pkrel, Oid pkindOid, Oid constraintOid)
 
static void createForeignKeyTriggers (Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
 
static void ATController (AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
 
static void ATPrepCmd (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
 
static void ATRewriteCatalogs (List **wqueue, LOCKMODE lockmode)
 
static void ATExecCmd (List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static void ATRewriteTables (AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
 
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)
 
static void ATTypedTableRecursion (List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
 
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)
 
static ObjectAddress ATExecAddColumn (List **wqueue, AlteredTableInfo *tab, Relation rel, ColumnDef *colDef, bool isOid, bool recurse, bool recursing, bool if_not_exists, LOCKMODE lockmode)
 
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 ATPrepAddOids (List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static void ATPrepDropNotNull (Relation rel, bool recurse, bool recursing)
 
static ObjectAddress ATExecDropNotNull (Relation rel, const char *colName, LOCKMODE lockmode)
 
static void ATPrepSetNotNull (Relation rel, bool recurse, bool recursing)
 
static ObjectAddress ATExecSetNotNull (AlteredTableInfo *tab, Relation rel, const char *colName, LOCKMODE lockmode)
 
static ObjectAddress ATExecColumnDefault (Relation rel, const char *colName, Node *newDefault, LOCKMODE lockmode)
 
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 ATPrepSetStatistics (Relation rel, const char *colName, int16 colNum, Node *newValue, 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)
 
static ObjectAddress ATExecDropColumn (List **wqueue, Relation rel, const char *colName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode)
 
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 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 (AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, LOCKMODE lockmode)
 
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)
 
static bool ATColumnChangeRequiresRewrite (Node *expr, AttrNumber varattno)
 
static ObjectAddress ATExecAlterColumnType (AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static ObjectAddress ATExecAlterColumnGenericOptions (Relation rel, const char *colName, List *options, LOCKMODE lockmode)
 
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 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 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 copy_relation_data (SMgrRelation rel, SMgrRelation dst, ForkNumber forkNum, char relpersistence)
 
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 (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)
 
static void ValidatePartitionConstraints (List **wqueue, Relation scanrel, List *scanrel_children, List *partConstraint, bool validate_default)
 
static ObjectAddress ATExecDetachPartition (Relation rel, RangeVar *name)
 
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 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)
 
void CheckTableNotInUse (Relation rel, const char *stmt)
 
Oid AlterTableLookupRelation (AlterTableStmt *stmt, LOCKMODE lockmode)
 
void AlterTable (Oid relid, LOCKMODE lockmode, AlterTableStmt *stmt)
 
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)
 
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)
 

Variables

static Liston_commits = NIL
 
static const struct dropmsgstrings dropmsgstringarray []
 

Macro Definition Documentation

◆ AT_NUM_PASSES

#define AT_NUM_PASSES   9

Definition at line 152 of file tablecmds.c.

Referenced by ATRewriteCatalogs().

◆ AT_PASS_ADD_COL

#define AT_PASS_ADD_COL   5 /* ADD COLUMN */

Definition at line 148 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_ADD_CONSTR

#define AT_PASS_ADD_CONSTR   7 /* ADD constraints, defaults */

Definition at line 150 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_ADD_INDEX

#define AT_PASS_ADD_INDEX   6 /* ADD indexes */

Definition at line 149 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_ALTER_TYPE

#define AT_PASS_ALTER_TYPE   1 /* ALTER COLUMN TYPE */

Definition at line 143 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATRewriteCatalogs().

◆ AT_PASS_COL_ATTRS

#define AT_PASS_COL_ATTRS   4 /* set other column attributes */

Definition at line 146 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_DROP

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

Definition at line 142 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_MISC

#define AT_PASS_MISC   8 /* other stuff */

Definition at line 151 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_OLD_CONSTR

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

Definition at line 145 of file tablecmds.c.

Referenced by ATPostAlterTypeParse().

◆ AT_PASS_OLD_INDEX

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

Definition at line 144 of file tablecmds.c.

Referenced by ATPostAlterTypeParse().

◆ AT_PASS_UNSET

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

Definition at line 141 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ ATT_COMPOSITE_TYPE

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 285 of file tablecmds.c.

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

◆ ATT_FOREIGN_TABLE

◆ ATT_INDEX

#define ATT_INDEX   0x0008

Definition at line 284 of file tablecmds.c.

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

◆ ATT_MATVIEW

#define ATT_MATVIEW   0x0004

Definition at line 283 of file tablecmds.c.

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

◆ ATT_TABLE

◆ ATT_VIEW

#define ATT_VIEW   0x0002

Definition at line 282 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 293 of file tablecmds.c.

Referenced by RemoveInheritance(), and StoreCatalogInheritance1().

Typedef Documentation

◆ AlteredTableInfo

◆ NewColumnValue

◆ NewConstraint

◆ OnCommitItem

Function Documentation

◆ add_column_collation_dependency()

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

Definition at line 5604 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

5605 {
5606  ObjectAddress myself,
5607  referenced;
5608 
5609  /* We know the default collation is pinned, so don't bother recording it */
5610  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
5611  {
5612  myself.classId = RelationRelationId;
5613  myself.objectId = relid;
5614  myself.objectSubId = attnum;
5615  referenced.classId = CollationRelationId;
5616  referenced.objectId = collid;
5617  referenced.objectSubId = 0;
5618  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
5619  }
5620 }
#define RelationRelationId
Definition: pg_class.h:29
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
#define OidIsValid(objectId)
Definition: c.h:586
#define DEFAULT_COLLATION_OID
Definition: pg_collation.h:75
#define CollationRelationId
Definition: pg_collation.h:30

◆ add_column_datatype_dependency()

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

Definition at line 5586 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

5587 {
5588  ObjectAddress myself,
5589  referenced;
5590 
5591  myself.classId = RelationRelationId;
5592  myself.objectId = relid;
5593  myself.objectSubId = attnum;
5594  referenced.classId = TypeRelationId;
5595  referenced.objectId = typid;
5596  referenced.objectSubId = 0;
5597  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
5598 }
#define RelationRelationId
Definition: pg_class.h:29
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
#define TypeRelationId
Definition: pg_type.h:34

◆ AlterIndexNamespaces()

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

Definition at line 12737 of file tablecmds.c.

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

Referenced by AlterTableNamespaceInternal().

12739 {
12740  List *indexList;
12741  ListCell *l;
12742 
12743  indexList = RelationGetIndexList(rel);
12744 
12745  foreach(l, indexList)
12746  {
12747  Oid indexOid = lfirst_oid(l);
12748  ObjectAddress thisobj;
12749 
12750  thisobj.classId = RelationRelationId;
12751  thisobj.objectId = indexOid;
12752  thisobj.objectSubId = 0;
12753 
12754  /*
12755  * Note: currently, the index will not have its own dependency on the
12756  * namespace, so we don't need to do changeDependencyFor(). There's no
12757  * row type in pg_type, either.
12758  *
12759  * XXX this objsMoved test may be pointless -- surely we have a single
12760  * dependency link from a relation to each index?
12761  */
12762  if (!object_address_present(&thisobj, objsMoved))
12763  {
12764  AlterRelationNamespaceInternal(classRel, indexOid,
12765  oldNspOid, newNspOid,
12766  false, objsMoved);
12767  add_exact_object_address(&thisobj, objsMoved);
12768  }
12769  }
12770 
12771  list_free(indexList);
12772 }
#define RelationRelationId
Definition: pg_class.h:29
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2220
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2160
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:12667
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4315
void list_free(List *list)
Definition: list.c:1133
Definition: pg_list.h:45
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ AlterRelationNamespaceInternal()

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

Definition at line 12667 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, NamespaceRelationId, NameStr, object_address_present(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, RelationRelationId, RELOID, SearchSysCacheCopy1, and HeapTupleData::t_self.

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

12671 {
12672  HeapTuple classTup;
12673  Form_pg_class classForm;
12674  ObjectAddress thisobj;
12675  bool already_done = false;
12676 
12677  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
12678  if (!HeapTupleIsValid(classTup))
12679  elog(ERROR, "cache lookup failed for relation %u", relOid);
12680  classForm = (Form_pg_class) GETSTRUCT(classTup);
12681 
12682  Assert(classForm->relnamespace == oldNspOid);
12683 
12684  thisobj.classId = RelationRelationId;
12685  thisobj.objectId = relOid;
12686  thisobj.objectSubId = 0;
12687 
12688  /*
12689  * If the object has already been moved, don't move it again. If it's
12690  * already in the right place, don't move it, but still fire the object
12691  * access hook.
12692  */
12693  already_done = object_address_present(&thisobj, objsMoved);
12694  if (!already_done && oldNspOid != newNspOid)
12695  {
12696  /* check for duplicate name (more friendly than unique-index failure) */
12697  if (get_relname_relid(NameStr(classForm->relname),
12698  newNspOid) != InvalidOid)
12699  ereport(ERROR,
12700  (errcode(ERRCODE_DUPLICATE_TABLE),
12701  errmsg("relation \"%s\" already exists in schema \"%s\"",
12702  NameStr(classForm->relname),
12703  get_namespace_name(newNspOid))));
12704 
12705  /* classTup is a copy, so OK to scribble on */
12706  classForm->relnamespace = newNspOid;
12707 
12708  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
12709 
12710  /* Update dependency on schema if caller said so */
12711  if (hasDependEntry &&
12713  relOid,
12715  oldNspOid,
12716  newNspOid) != 1)
12717  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
12718  NameStr(classForm->relname));
12719  }
12720  if (!already_done)
12721  {
12722  add_exact_object_address(&thisobj, objsMoved);
12723 
12725  }
12726 
12727  heap_freetuple(classTup);
12728 }
#define NamespaceRelationId
Definition: pg_namespace.h:34
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define RelationRelationId
Definition: pg_class.h:29
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2220
int errcode(int sqlerrcode)
Definition: elog.c:575
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2160
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1702
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3066
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:680
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
int errmsg(const char *fmt,...)
Definition: elog.c:797
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:295
#define NameStr(name)
Definition: c.h:557
#define elog
Definition: elog.h:219

◆ AlterSeqNamespaces()

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

Definition at line 12782 of file tablecmds.c.

References AccessShareLock, AlterRelationNamespaceInternal(), AlterTypeNamespaceInternal(), Anum_pg_depend_refclassid, Anum_pg_depend_refobjid, BTEqualStrategyNumber, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DependReferenceIndexId, DependRelationId, GETSTRUCT, heap_open(), HeapTupleIsValid, NoLock, ObjectIdGetDatum, relation_close(), relation_open(), RelationGetForm, RelationGetRelid, RelationRelationId, DropRelationCallbackState::relkind, RELKIND_SEQUENCE, ScanKeyInit(), systable_beginscan(), systable_endscan(), and systable_getnext().

Referenced by AlterTableNamespaceInternal().

12785 {
12786  Relation depRel;
12787  SysScanDesc scan;
12788  ScanKeyData key[2];
12789  HeapTuple tup;
12790 
12791  /*
12792  * SERIAL sequences are those having an auto dependency on one of the
12793  * table's columns (we don't care *which* column, exactly).
12794  */
12796 
12797  ScanKeyInit(&key[0],
12799  BTEqualStrategyNumber, F_OIDEQ,
12801  ScanKeyInit(&key[1],
12803  BTEqualStrategyNumber, F_OIDEQ,
12805  /* we leave refobjsubid unspecified */
12806 
12807  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
12808  NULL, 2, key);
12809 
12810  while (HeapTupleIsValid(tup = systable_getnext(scan)))
12811  {
12812  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
12813  Relation seqRel;
12814 
12815  /* skip dependencies other than auto dependencies on columns */
12816  if (depForm->refobjsubid == 0 ||
12817  depForm->classid != RelationRelationId ||
12818  depForm->objsubid != 0 ||
12819  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
12820  continue;
12821 
12822  /* Use relation_open just in case it's an index */
12823  seqRel = relation_open(depForm->objid, lockmode);
12824 
12825  /* skip non-sequence relations */
12826  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
12827  {
12828  /* No need to keep the lock */
12829  relation_close(seqRel, lockmode);
12830  continue;
12831  }
12832 
12833  /* Fix the pg_class and pg_depend entries */
12834  AlterRelationNamespaceInternal(classRel, depForm->objid,
12835  oldNspOid, newNspOid,
12836  true, objsMoved);
12837 
12838  /*
12839  * Sequences have entries in pg_type. We need to be careful to move
12840  * them to the new namespace, too.
12841  */
12843  newNspOid, false, false, objsMoved);
12844 
12845  /* Now we can close it. Keep the lock till end of transaction. */
12846  relation_close(seqRel, NoLock);
12847  }
12848 
12849  systable_endscan(scan);
12850 
12852 }
#define Anum_pg_depend_refobjid
Definition: pg_depend.h:72
#define Anum_pg_depend_refclassid
Definition: pg_depend.h:71
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define RelationGetForm(relation)
Definition: rel.h:419
#define RelationRelationId
Definition: pg_class.h:29
#define DependReferenceIndexId
Definition: indexing.h:147
#define DependRelationId
Definition: pg_depend.h:29
#define AccessShareLock
Definition: lockdefs.h:36
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3580
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define NoLock
Definition: lockdefs.h:34
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:61
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12667
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120
#define RELKIND_SEQUENCE
Definition: pg_class.h:162
#define RelationGetRelid(relation)
Definition: rel.h:425
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ AlterTable()

void AlterTable ( Oid  relid,
LOCKMODE  lockmode,
AlterTableStmt stmt 
)

Definition at line 3141 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3142 {
3143  Relation rel;
3144 
3145  /* Caller is required to provide an adequate lock. */
3146  rel = relation_open(relid, NoLock);
3147 
3148  CheckTableNotInUse(rel, "ALTER TABLE");
3149 
3150  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode);
3151 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3459
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3062
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1699
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 3210 of file tablecmds.c.

References AccessExclusiveLock, AlterTableGetRelOptionsLockLevel(), AT_AddColumn, AT_AddColumnToView, AT_AddConstraint, AT_AddConstraintRecurse, AT_AddIdentity, AT_AddIndex, AT_AddIndexConstraint, AT_AddInherit, AT_AddOf, AT_AddOids, AT_AlterColumnGenericOptions, AT_AlterColumnType, AT_AlterConstraint, AT_AttachPartition, AT_ChangeOwner, AT_ClusterOn, AT_ColumnDefault, AT_DetachPartition, AT_DisableRowSecurity, AT_DisableRule, AT_DisableTrig, AT_DisableTrigAll, AT_DisableTrigUser, AT_DropCluster, AT_DropColumn, AT_DropConstraint, 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_ProcessedConstraint, 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().

3211 {
3212  /*
3213  * This only works if we read catalog tables using MVCC snapshots.
3214  */
3215  ListCell *lcmd;
3217 
3218  foreach(lcmd, cmds)
3219  {
3220  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3221  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
3222 
3223  switch (cmd->subtype)
3224  {
3225  /*
3226  * These subcommands rewrite the heap, so require full locks.
3227  */
3228  case AT_AddColumn: /* may rewrite heap, in some cases and visible
3229  * to SELECT */
3230  case AT_SetTableSpace: /* must rewrite heap */
3231  case AT_AlterColumnType: /* must rewrite heap */
3232  case AT_AddOids: /* must rewrite heap */
3233  cmd_lockmode = AccessExclusiveLock;
3234  break;
3235 
3236  /*
3237  * These subcommands may require addition of toast tables. If
3238  * we add a toast table to a table currently being scanned, we
3239  * might miss data added to the new toast table by concurrent
3240  * insert transactions.
3241  */
3242  case AT_SetStorage: /* may add toast tables, see
3243  * ATRewriteCatalogs() */
3244  cmd_lockmode = AccessExclusiveLock;
3245  break;
3246 
3247  /*
3248  * Removing constraints can affect SELECTs that have been
3249  * optimised assuming the constraint holds true.
3250  */
3251  case AT_DropConstraint: /* as DROP INDEX */
3252  case AT_DropNotNull: /* may change some SQL plans */
3253  cmd_lockmode = AccessExclusiveLock;
3254  break;
3255 
3256  /*
3257  * Subcommands that may be visible to concurrent SELECTs
3258  */
3259  case AT_DropColumn: /* change visible to SELECT */
3260  case AT_AddColumnToView: /* CREATE VIEW */
3261  case AT_DropOids: /* calls AT_DropColumn */
3262  case AT_EnableAlwaysRule: /* may change SELECT rules */
3263  case AT_EnableReplicaRule: /* may change SELECT rules */
3264  case AT_EnableRule: /* may change SELECT rules */
3265  case AT_DisableRule: /* may change SELECT rules */
3266  cmd_lockmode = AccessExclusiveLock;
3267  break;
3268 
3269  /*
3270  * Changing owner may remove implicit SELECT privileges
3271  */
3272  case AT_ChangeOwner: /* change visible to SELECT */
3273  cmd_lockmode = AccessExclusiveLock;
3274  break;
3275 
3276  /*
3277  * Changing foreign table options may affect optimization.
3278  */
3279  case AT_GenericOptions:
3281  cmd_lockmode = AccessExclusiveLock;
3282  break;
3283 
3284  /*
3285  * These subcommands affect write operations only.
3286  */
3287  case AT_EnableTrig:
3288  case AT_EnableAlwaysTrig:
3289  case AT_EnableReplicaTrig:
3290  case AT_EnableTrigAll:
3291  case AT_EnableTrigUser:
3292  case AT_DisableTrig:
3293  case AT_DisableTrigAll:
3294  case AT_DisableTrigUser:
3295  cmd_lockmode = ShareRowExclusiveLock;
3296  break;
3297 
3298  /*
3299  * These subcommands affect write operations only. XXX
3300  * Theoretically, these could be ShareRowExclusiveLock.
3301  */
3302  case AT_ColumnDefault:
3303  case AT_AlterConstraint:
3304  case AT_AddIndex: /* from ADD CONSTRAINT */
3305  case AT_AddIndexConstraint:
3306  case AT_ReplicaIdentity:
3307  case AT_SetNotNull:
3308  case AT_EnableRowSecurity:
3309  case AT_DisableRowSecurity:
3310  case AT_ForceRowSecurity:
3311  case AT_NoForceRowSecurity:
3312  case AT_AddIdentity:
3313  case AT_DropIdentity:
3314  case AT_SetIdentity:
3315  cmd_lockmode = AccessExclusiveLock;
3316  break;
3317 
3318  case AT_AddConstraint:
3319  case AT_ProcessedConstraint: /* becomes AT_AddConstraint */
3320  case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
3321  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
3322  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
3323  if (IsA(cmd->def, Constraint))
3324  {
3325  Constraint *con = (Constraint *) cmd->def;
3326 
3327  switch (con->contype)
3328  {
3329  case CONSTR_EXCLUSION:
3330  case CONSTR_PRIMARY:
3331  case CONSTR_UNIQUE:
3332 
3333  /*
3334  * Cases essentially the same as CREATE INDEX. We
3335  * could reduce the lock strength to ShareLock if
3336  * we can work out how to allow concurrent catalog
3337  * updates. XXX Might be set down to
3338  * ShareRowExclusiveLock but requires further
3339  * analysis.
3340  */
3341  cmd_lockmode = AccessExclusiveLock;
3342  break;
3343  case CONSTR_FOREIGN:
3344 
3345  /*
3346  * We add triggers to both tables when we add a
3347  * Foreign Key, so the lock level must be at least
3348  * as strong as CREATE TRIGGER.
3349  */
3350  cmd_lockmode = ShareRowExclusiveLock;
3351  break;
3352 
3353  default:
3354  cmd_lockmode = AccessExclusiveLock;
3355  }
3356  }
3357  break;
3358 
3359  /*
3360  * These subcommands affect inheritance behaviour. Queries
3361  * started before us will continue to see the old inheritance
3362  * behaviour, while queries started after we commit will see
3363  * new behaviour. No need to prevent reads or writes to the
3364  * subtable while we hook it up though. Changing the TupDesc
3365  * may be a problem, so keep highest lock.
3366  */
3367  case AT_AddInherit:
3368  case AT_DropInherit:
3369  cmd_lockmode = AccessExclusiveLock;
3370  break;
3371 
3372  /*
3373  * These subcommands affect implicit row type conversion. They
3374  * have affects similar to CREATE/DROP CAST on queries. don't
3375  * provide for invalidating parse trees as a result of such
3376  * changes, so we keep these at AccessExclusiveLock.
3377  */
3378  case AT_AddOf:
3379  case AT_DropOf:
3380  cmd_lockmode = AccessExclusiveLock;
3381  break;
3382 
3383  /*
3384  * Only used by CREATE OR REPLACE VIEW which must conflict
3385  * with an SELECTs currently using the view.
3386  */
3387  case AT_ReplaceRelOptions:
3388  cmd_lockmode = AccessExclusiveLock;
3389  break;
3390 
3391  /*
3392  * These subcommands affect general strategies for performance
3393  * and maintenance, though don't change the semantic results
3394  * from normal data reads and writes. Delaying an ALTER TABLE
3395  * behind currently active writes only delays the point where
3396  * the new strategy begins to take effect, so there is no
3397  * benefit in waiting. In this case the minimum restriction
3398  * applies: we don't currently allow concurrent catalog
3399  * updates.
3400  */
3401  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
3402  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
3403  case AT_DropCluster: /* Uses MVCC in getIndexes() */
3404  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
3405  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
3406  cmd_lockmode = ShareUpdateExclusiveLock;
3407  break;
3408 
3409  case AT_SetLogged:
3410  case AT_SetUnLogged:
3411  cmd_lockmode = AccessExclusiveLock;
3412  break;
3413 
3414  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
3415  cmd_lockmode = ShareUpdateExclusiveLock;
3416  break;
3417 
3418  /*
3419  * Rel options are more complex than first appears. Options
3420  * are set here for tables, views and indexes; for historical
3421  * reasons these can all be used with ALTER TABLE, so we can't
3422  * decide between them using the basic grammar.
3423  */
3424  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
3425  * getTables() */
3426  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
3427  * getTables() */
3428  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
3429  break;
3430 
3431  case AT_AttachPartition:
3432  case AT_DetachPartition:
3433  cmd_lockmode = AccessExclusiveLock;
3434  break;
3435 
3436  default: /* oops */
3437  elog(ERROR, "unrecognized alter table type: %d",
3438  (int) cmd->subtype);
3439  break;
3440  }
3441 
3442  /*
3443  * Take the greatest lockmode from any subcommand
3444  */
3445  if (cmd_lockmode > lockmode)
3446  lockmode = cmd_lockmode;
3447  }
3448 
3449  return lockmode;
3450 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
int LOCKMODE
Definition: lockdefs.h:26
AlterTableType subtype
Definition: parsenodes.h:1787
#define ERROR
Definition: elog.h:43
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define lfirst(lc)
Definition: pg_list.h:106
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList)
Definition: reloptions.c:1540
#define AccessExclusiveLock
Definition: lockdefs.h:45
ConstrType contype
Definition: parsenodes.h:2092
#define elog
Definition: elog.h:219
Definition: pg_list.h:45

◆ AlterTableInternal()

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

Definition at line 3165 of file tablecmds.c.

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

Referenced by AlterTableMoveAll(), DefineVirtualRelation(), and index_check_primary_key().

3166 {
3167  Relation rel;
3168  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
3169 
3170  rel = relation_open(relid, lockmode);
3171 
3173 
3174  ATController(NULL, rel, cmds, recurse, lockmode);
3175 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3459
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:3210
void EventTriggerAlterTableRelid(Oid objectId)
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3091 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3092 {
3093  return RangeVarGetRelidExtended(stmt->relation, lockmode, stmt->missing_ok, false,
3095  (void *) stmt);
3096 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:218
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:13144
RangeVar * relation
Definition: parsenodes.h:1699

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 10745 of file tablecmds.c.

References AccessExclusiveLock, AccessShareLock, ACL_CREATE, ACL_KIND_CLASS, ACL_KIND_TABLESPACE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTableInternal(), Anum_pg_class_reltablespace, AT_SetTableSpace, BTEqualStrategyNumber, ConditionalLockRelationOid(), ereport, errcode(), errmsg(), ERROR, EventTriggerAlterTableEnd(), EventTriggerAlterTableStart(), ForwardScanDirection, get_namespace_name(), get_tablespace_name(), get_tablespace_oid(), GETSTRUCT, GetUserId(), GLOBALTABLESPACE_OID, heap_beginscan_catalog(), heap_close, heap_endscan(), heap_getnext(), heap_open(), HeapTupleGetOid, InvalidOid, isAnyTempNamespace(), IsSystemNamespace(), 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, ObjectIdGetDatum, AlterTableMoveAllStmt::objtype, OidIsValid, AlterTableMoveAllStmt::orig_tablespacename, pg_class_ownercheck(), pg_tablespace_aclcheck(), PG_TOAST_NAMESPACE, RelationRelationId, RELKIND_INDEX, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, AlterTableMoveAllStmt::roles, roleSpecsToIds(), ScanKeyInit(), and AlterTableCmd::subtype.

Referenced by ProcessUtilitySlow().

10746 {
10747  List *relations = NIL;
10748  ListCell *l;
10749  ScanKeyData key[1];
10750  Relation rel;
10751  HeapScanDesc scan;
10752  HeapTuple tuple;
10753  Oid orig_tablespaceoid;
10754  Oid new_tablespaceoid;
10755  List *role_oids = roleSpecsToIds(stmt->roles);
10756 
10757  /* Ensure we were not asked to move something we can't */
10758  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
10759  stmt->objtype != OBJECT_MATVIEW)
10760  ereport(ERROR,
10761  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
10762  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
10763 
10764  /* Get the orig and new tablespace OIDs */
10765  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
10766  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
10767 
10768  /* Can't move shared relations in to or out of pg_global */
10769  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
10770  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
10771  new_tablespaceoid == GLOBALTABLESPACE_OID)
10772  ereport(ERROR,
10773  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
10774  errmsg("cannot move relations in to or out of pg_global tablespace")));
10775 
10776  /*
10777  * Must have CREATE rights on the new tablespace, unless it is the
10778  * database default tablespace (which all users implicitly have CREATE
10779  * rights on).
10780  */
10781  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
10782  {
10783  AclResult aclresult;
10784 
10785  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
10786  ACL_CREATE);
10787  if (aclresult != ACLCHECK_OK)
10789  get_tablespace_name(new_tablespaceoid));
10790  }
10791 
10792  /*
10793  * Now that the checks are done, check if we should set either to
10794  * InvalidOid because it is our database's default tablespace.
10795  */
10796  if (orig_tablespaceoid == MyDatabaseTableSpace)
10797  orig_tablespaceoid = InvalidOid;
10798 
10799  if (new_tablespaceoid == MyDatabaseTableSpace)
10800  new_tablespaceoid = InvalidOid;
10801 
10802  /* no-op */
10803  if (orig_tablespaceoid == new_tablespaceoid)
10804  return new_tablespaceoid;
10805 
10806  /*
10807  * Walk the list of objects in the tablespace and move them. This will
10808  * only find objects in our database, of course.
10809  */
10810  ScanKeyInit(&key[0],
10812  BTEqualStrategyNumber, F_OIDEQ,
10813  ObjectIdGetDatum(orig_tablespaceoid));
10814 
10816  scan = heap_beginscan_catalog(rel, 1, key);
10817  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
10818  {
10819  Oid relOid = HeapTupleGetOid(tuple);
10820  Form_pg_class relForm;
10821 
10822  relForm = (Form_pg_class) GETSTRUCT(tuple);
10823 
10824  /*
10825  * Do not move objects in pg_catalog as part of this, if an admin
10826  * really wishes to do so, they can issue the individual ALTER
10827  * commands directly.
10828  *
10829  * Also, explicitly avoid any shared tables, temp tables, or TOAST
10830  * (TOAST will be moved with the main table).
10831  */
10832  if (IsSystemNamespace(relForm->relnamespace) || relForm->relisshared ||
10833  isAnyTempNamespace(relForm->relnamespace) ||
10834  relForm->relnamespace == PG_TOAST_NAMESPACE)
10835  continue;
10836 
10837  /* Only move the object type requested */
10838  if ((stmt->objtype == OBJECT_TABLE &&
10839  relForm->relkind != RELKIND_RELATION &&
10840  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
10841  (stmt->objtype == OBJECT_INDEX &&
10842  relForm->relkind != RELKIND_INDEX) ||
10843  (stmt->objtype == OBJECT_MATVIEW &&
10844  relForm->relkind != RELKIND_MATVIEW))
10845  continue;
10846 
10847  /* Check if we are only moving objects owned by certain roles */
10848  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
10849  continue;
10850 
10851  /*
10852  * Handle permissions-checking here since we are locking the tables
10853  * and also to avoid doing a bunch of work only to fail part-way. Note
10854  * that permissions will also be checked by AlterTableInternal().
10855  *
10856  * Caller must be considered an owner on the table to move it.
10857  */
10858  if (!pg_class_ownercheck(relOid, GetUserId()))
10860  NameStr(relForm->relname));
10861 
10862  if (stmt->nowait &&
10864  ereport(ERROR,
10865  (errcode(ERRCODE_OBJECT_IN_USE),
10866  errmsg("aborting because lock on relation \"%s.%s\" is not available",
10867  get_namespace_name(relForm->relnamespace),
10868  NameStr(relForm->relname))));
10869  else
10871 
10872  /* Add to our list of objects to move */
10873  relations = lappend_oid(relations, relOid);
10874  }
10875 
10876  heap_endscan(scan);
10878 
10879  if (relations == NIL)
10880  ereport(NOTICE,
10881  (errcode(ERRCODE_NO_DATA_FOUND),
10882  errmsg("no matching relations in tablespace \"%s\" found",
10883  orig_tablespaceoid == InvalidOid ? "(database default)" :
10884  get_tablespace_name(orig_tablespaceoid))));
10885 
10886  /* Everything is locked, loop through and move all of the relations. */
10887  foreach(l, relations)
10888  {
10889  List *cmds = NIL;
10891 
10892  cmd->subtype = AT_SetTableSpace;
10893  cmd->name = stmt->new_tablespacename;
10894 
10895  cmds = lappend(cmds, cmd);
10896 
10898  /* OID is set by AlterTableInternal */
10899  AlterTableInternal(lfirst_oid(l), cmds, false);
10901  }
10902 
10903  return new_tablespaceoid;
10904 }
#define NIL
Definition: pg_list.h:69
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:138
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1380
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4554
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1565
Oid GetUserId(void)
Definition: miscinit.c:284
#define RelationRelationId
Definition: pg_class.h:29
#define Anum_pg_class_reltablespace
Definition: pg_class.h:110
#define RELKIND_MATVIEW
Definition: pg_class.h:165
#define AccessShareLock
Definition: lockdefs.h:36
#define GLOBALTABLESPACE_OID
Definition: pg_tablespace.h:64
Definition: nodes.h:512
int errcode(int sqlerrcode)
Definition: elog.c:575
AlterTableType subtype
Definition: parsenodes.h:1787
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
#define PG_TOAST_NAMESPACE
Definition: pg_namespace.h:74
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:586
Oid MyDatabaseTableSpace
Definition: globals.c:79
void EventTriggerAlterTableStart(Node *parsetree)
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:82
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3066
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3457
HeapScanDesc heap_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
Definition: heapam.c:1405
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
AclResult
Definition: acl.h:178
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1808
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
bool IsSystemNamespace(Oid namespaceId)
Definition: catalog.c:163
#define InvalidOid
Definition: postgres_ext.h:36
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:560
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1396
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4604
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:3165
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1426
#define NameStr(name)
Definition: c.h:557
#define RELKIND_INDEX
Definition: pg_class.h:161
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3156
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:700
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
#define RELKIND_RELATION
Definition: pg_class.h:160
Definition: pg_list.h:45
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:108
void EventTriggerAlterTableEnd(void)

◆ AlterTableNamespace()

ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 12558 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, RelationRelationId, OnCommitItem::relid, RELKIND_SEQUENCE, and sequenceIsOwned().

Referenced by ExecAlterObjectSchemaStmt().

12559 {
12560  Relation rel;
12561  Oid relid;
12562  Oid oldNspOid;
12563  Oid nspOid;
12564  RangeVar *newrv;
12565  ObjectAddresses *objsMoved;
12566  ObjectAddress myself;
12567 
12569  stmt->missing_ok, false,
12571  (void *) stmt);
12572 
12573  if (!OidIsValid(relid))
12574  {
12575  ereport(NOTICE,
12576  (errmsg("relation \"%s\" does not exist, skipping",
12577  stmt->relation->relname)));
12578  return InvalidObjectAddress;
12579  }
12580 
12581  rel = relation_open(relid, NoLock);
12582 
12583  oldNspOid = RelationGetNamespace(rel);
12584 
12585  /* If it's an owned sequence, disallow moving it by itself. */
12586  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
12587  {
12588  Oid tableId;
12589  int32 colId;
12590 
12591  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
12592  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
12593  ereport(ERROR,
12594  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12595  errmsg("cannot move an owned sequence into another schema"),
12596  errdetail("Sequence \"%s\" is linked to table \"%s\".",
12598  get_rel_name(tableId))));
12599  }
12600 
12601  /* Get and lock schema OID and check its permissions. */
12602  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
12603  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
12604 
12605  /* common checks on switching namespaces */
12606  CheckSetNamespace(oldNspOid, nspOid);
12607 
12608  objsMoved = new_object_addresses();
12609  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
12610  free_object_addresses(objsMoved);
12611 
12612  ObjectAddressSet(myself, RelationRelationId, relid);
12613 
12614  if (oldschema)
12615  *oldschema = oldNspOid;
12616 
12617  /* close rel, but keep lock until commit */
12618  relation_close(rel, NoLock);
12619 
12620  return myself;
12621 }
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:500
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:218
#define RelationRelationId
Definition: pg_class.h:29
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2105
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2376
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:586
signed int int32
Definition: c.h:294
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:43
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12629
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:13144
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define RelationGetRelationName(relation)
Definition: rel.h:445
#define ereport(elevel, rest)
Definition: elog.h:122
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2928
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:508
#define NOTICE
Definition: elog.h:37
#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:797
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1120
#define RELKIND_SEQUENCE
Definition: pg_class.h:162
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1745
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:421
#define RelationGetNamespace(relation)
Definition: rel.h:452

◆ AlterTableNamespaceInternal()

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

Definition at line 12629 of file tablecmds.c.

References AccessExclusiveLock, AlterConstraintNamespaces(), AlterIndexNamespaces(), AlterRelationNamespaceInternal(), AlterSeqNamespaces(), AlterTypeNamespaceInternal(), Assert, heap_close, heap_open(), RelationData::rd_rel, RelationGetRelid, RelationRelationId, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, and RowExclusiveLock.

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

12631 {
12632  Relation classRel;
12633 
12634  Assert(objsMoved != NULL);
12635 
12636  /* OK, modify the pg_class row and pg_depend entry */
12638 
12639  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
12640  nspOid, true, objsMoved);
12641 
12642  /* Fix the table's row type too */
12643  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
12644  nspOid, false, false, objsMoved);
12645 
12646  /* Fix other dependent stuff */
12647  if (rel->rd_rel->relkind == RELKIND_RELATION ||
12648  rel->rd_rel->relkind == RELKIND_MATVIEW ||
12649  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12650  {
12651  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
12652  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
12653  objsMoved, AccessExclusiveLock);
12654  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
12655  false, objsMoved);
12656  }
12657 
12658  heap_close(classRel, RowExclusiveLock);
12659 }
#define RelationRelationId
Definition: pg_class.h:29
#define RELKIND_MATVIEW
Definition: pg_class.h:165
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3580
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12737
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:12782
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define Assert(condition)
Definition: c.h:680
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12667
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RelationGetRelid(relation)
Definition: rel.h:425

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

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

Referenced by ATExecAddConstraint().

6931 {
6932  List *newcons;
6933  ListCell *lcon;
6934  List *children;
6935  ListCell *child;
6937 
6938  /* At top level, permission check was done in ATPrepCmd, else do it */
6939  if (recursing)
6941 
6942  /*
6943  * Call AddRelationNewConstraints to do the work, making sure it works on
6944  * a copy of the Constraint so transformExpr can't modify the original. It
6945  * returns a list of cooked constraints.
6946  *
6947  * If the constraint ends up getting merged with a pre-existing one, it's
6948  * omitted from the returned list, which is what we want: we do not need
6949  * to do any validation work. That can only happen at child tables,
6950  * though, since we disallow merging at the top level.
6951  */
6952  newcons = AddRelationNewConstraints(rel, NIL,
6953  list_make1(copyObject(constr)),
6954  recursing | is_readd, /* allow_merge */
6955  !recursing, /* is_local */
6956  is_readd); /* is_internal */
6957 
6958  /* we don't expect more than one constraint here */
6959  Assert(list_length(newcons) <= 1);
6960 
6961  /* Add each to-be-validated constraint to Phase 3's queue */
6962  foreach(lcon, newcons)
6963  {
6964  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
6965 
6966  if (!ccon->skip_validation)
6967  {
6968  NewConstraint *newcon;
6969 
6970  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
6971  newcon->name = ccon->name;
6972  newcon->contype = ccon->contype;
6973  newcon->qual = ccon->expr;
6974 
6975  tab->constraints = lappend(tab->constraints, newcon);
6976  }
6977 
6978  /* Save the actually assigned name if it was defaulted */
6979  if (constr->conname == NULL)
6980  constr->conname = ccon->name;
6981 
6982  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
6983  }
6984 
6985  /* At this point we must have a locked-down name to use */
6986  Assert(constr->conname != NULL);
6987 
6988  /* Advance command counter in case same table is visited multiple times */
6990 
6991  /*
6992  * If the constraint got merged with an existing constraint, we're done.
6993  * We mustn't recurse to child tables in this case, because they've
6994  * already got the constraint, and visiting them again would lead to an
6995  * incorrect value for coninhcount.
6996  */
6997  if (newcons == NIL)
6998  return address;
6999 
7000  /*
7001  * If adding a NO INHERIT constraint, no need to find our children.
7002  */
7003  if (constr->is_no_inherit)
7004  return address;
7005 
7006  /*
7007  * Propagate to children as appropriate. Unlike most other ALTER
7008  * routines, we have to do this one level of recursion at a time; we can't
7009  * use find_all_inheritors to do it in one pass.
7010  */
7011  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
7012 
7013  /*
7014  * Check if ONLY was specified with ALTER TABLE. If so, allow the
7015  * constraint creation only if there are no children currently. Error out
7016  * otherwise.
7017  */
7018  if (!recurse && children != NIL)
7019  ereport(ERROR,
7020  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7021  errmsg("constraint must be added to child tables too")));
7022 
7023  foreach(child, children)
7024  {
7025  Oid childrelid = lfirst_oid(child);
7026  Relation childrel;
7027  AlteredTableInfo *childtab;
7028 
7029  /* find_inheritance_children already got lock */
7030  childrel = heap_open(childrelid, NoLock);
7031  CheckTableNotInUse(childrel, "ALTER TABLE");
7032 
7033  /* Find or create work queue entry for this table */
7034  childtab = ATGetQueueEntry(wqueue, childrel);
7035 
7036  /* Recurse to child */
7037  ATAddCheckConstraint(wqueue, childtab, childrel,
7038  constr, recurse, true, is_readd, lockmode);
7039 
7040  heap_close(childrel, NoLock);
7041  }
7042 
7043  return address;
7044 }
#define NIL
Definition: pg_list.h:69
char * name
Definition: tablecmds.c:184
Node * qual
Definition: tablecmds.c:189
int errcode(int sqlerrcode)
Definition: elog.c:575
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:6928
#define heap_close(r, l)
Definition: heapam.h:97
char * conname
Definition: parsenodes.h:2095
unsigned int Oid
Definition: postgres_ext.h:31
#define ATT_TABLE
Definition: tablecmds.c:281
List * constraints
Definition: tablecmds.c:163
#define list_make1(x1)
Definition: pg_list.h:139
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:4699
bool skip_validation
Definition: heap.h:35
ConstrType contype
Definition: heap.h:30
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3062
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
ConstrType contype
Definition: tablecmds.c:185
void * palloc0(Size size)
Definition: mcxt.c:864
void CommandCounterIncrement(void)
Definition: xact.c:915
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
bool is_no_inherit
Definition: parsenodes.h:2101
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:57
#define Assert(condition)
Definition: c.h:680
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
Oid conoid
Definition: heap.h:31
Node * expr
Definition: heap.h:34
static void ATSimplePermissions(Relation rel, int allowed_targets)
Definition: tablecmds.c:4736
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define copyObject(obj)
Definition: nodes.h:625
Definition: pg_list.h:45
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:286
char * name
Definition: heap.h:32
#define RelationGetRelid(relation)
Definition: rel.h:425
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal)
Definition: heap.c:2229
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ ATAddForeignKeyConstraint()

static ObjectAddress ATAddForeignKeyConstraint ( AlteredTableInfo tab,
Relation  rel,
Constraint fkconstraint,
LOCKMODE  lockmode 
)
static

Definition at line 7055 of file tablecmds.c.

References allowSystemTableMods, Assert, BTEqualStrategyNumber, BTREE_AM_OID, can_coerce_type(), checkFkeyPermissions(), CLAOID, COERCION_IMPLICIT, NewConstraint::conid, Constraint::conname, CONSTR_FOREIGN, CONSTRAINT_FOREIGN, ConstraintRelationId, AlteredTableInfo::constraints, NewConstraint::contype, CreateConstraintEntry(), createForeignKeyTriggers(), Constraint::deferrable, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, findFkeyCast(), Constraint::fk_attrs, Constraint::fk_del_action, Constraint::fk_matchtype, Constraint::fk_upd_action, format_type_be(), get_opfamily_member(), getBaseType(), GETSTRUCT, heap_close, heap_open(), heap_openrv(), HeapTupleIsValid, i, INDEX_MAX_KEYS, Constraint::initdeferred, Constraint::initially_valid, InvalidOid, IsPolymorphicType, IsSystemRelation(), lappend(), lfirst_oid, list_head(), list_length(), list_nth(), lnext, MemSet, NewConstraint::name, NIL, NoLock, ObjectAddressSet, ObjectIdGetDatum, OidIsValid, Constraint::old_conpfeqop, Constraint::old_pktable_oid, AlteredTableInfo::oldDesc, palloc0(), Constraint::pk_attrs, Constraint::pktable, NewConstraint::qual, RelationData::rd_islocaltemp, RelationData::rd_rel, NewConstraint::refindid, NewConstraint::refrelid, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RELPERSISTENCE_PERMANENT, RELPERSISTENCE_TEMP, RELPERSISTENCE_UNLOGGED, SearchSysCache1(), ShareRowExclusiveLock, Constraint::skip_validation, strVal, transformColumnNameList(), transformFkeyCheckAttrs(), transformFkeyGetPrimaryKey(), and TupleDescAttr.

Referenced by ATExecAddConstraint().

7057 {
7058  Relation pkrel;
7059  int16 pkattnum[INDEX_MAX_KEYS];
7060  int16 fkattnum[INDEX_MAX_KEYS];
7061  Oid pktypoid[INDEX_MAX_KEYS];
7062  Oid fktypoid[INDEX_MAX_KEYS];
7063  Oid opclasses[INDEX_MAX_KEYS];
7064  Oid pfeqoperators[INDEX_MAX_KEYS];
7065  Oid ppeqoperators[INDEX_MAX_KEYS];
7066  Oid ffeqoperators[INDEX_MAX_KEYS];
7067  int i;
7068  int numfks,
7069  numpks;
7070  Oid indexOid;
7071  Oid constrOid;
7072  bool old_check_ok;
7073  ObjectAddress address;
7074  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
7075 
7076  /*
7077  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
7078  * delete rows out from under us.
7079  */
7080  if (OidIsValid(fkconstraint->old_pktable_oid))
7081  pkrel = heap_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
7082  else
7083  pkrel = heap_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
7084 
7085  /*
7086  * Validity checks (permission checks wait till we have the column
7087  * numbers)
7088  */
7089  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7090  ereport(ERROR,
7091  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7092  errmsg("cannot reference partitioned table \"%s\"",
7093  RelationGetRelationName(pkrel))));
7094 
7095  if (pkrel->rd_rel->relkind != RELKIND_RELATION)
7096  ereport(ERROR,
7097  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7098  errmsg("referenced relation \"%s\" is not a table",
7099  RelationGetRelationName(pkrel))));
7100 
7101  if (!allowSystemTableMods && IsSystemRelation(pkrel))
7102  ereport(ERROR,
7103  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
7104  errmsg("permission denied: \"%s\" is a system catalog",
7105  RelationGetRelationName(pkrel))));
7106 
7107  /*
7108  * References from permanent or unlogged tables to temp tables, and from
7109  * permanent tables to unlogged tables, are disallowed because the
7110  * referenced data can vanish out from under us. References from temp
7111  * tables to any other table type are also disallowed, because other
7112  * backends might need to run the RI triggers on the perm table, but they
7113  * can't reliably see tuples in the local buffers of other backends.
7114  */
7115  switch (rel->rd_rel->relpersistence)
7116  {
7118  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
7119  ereport(ERROR,
7120  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7121  errmsg("constraints on permanent tables may reference only permanent tables")));
7122  break;
7124  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT
7125  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
7126  ereport(ERROR,
7127  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7128  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
7129  break;
7130  case RELPERSISTENCE_TEMP:
7131  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
7132  ereport(ERROR,
7133  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7134  errmsg("constraints on temporary tables may reference only temporary tables")));
7135  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
7136  ereport(ERROR,
7137  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7138  errmsg("constraints on temporary tables must involve temporary tables of this session")));
7139  break;
7140  }
7141 
7142  /*
7143  * Look up the referencing attributes to make sure they exist, and record
7144  * their attnums and type OIDs.
7145  */
7146  MemSet(pkattnum, 0, sizeof(pkattnum));
7147  MemSet(fkattnum, 0, sizeof(fkattnum));
7148  MemSet(pktypoid, 0, sizeof(pktypoid));
7149  MemSet(fktypoid, 0, sizeof(fktypoid));
7150  MemSet(opclasses, 0, sizeof(opclasses));
7151  MemSet(pfeqoperators, 0, sizeof(pfeqoperators));
7152  MemSet(ppeqoperators, 0, sizeof(ppeqoperators));
7153  MemSet(ffeqoperators, 0, sizeof(ffeqoperators));
7154 
7156  fkconstraint->fk_attrs,
7157  fkattnum, fktypoid);
7158 
7159  /*
7160  * If the attribute list for the referenced table was omitted, lookup the
7161  * definition of the primary key and use it. Otherwise, validate the
7162  * supplied attribute list. In either case, discover the index OID and
7163  * index opclasses, and the attnums and type OIDs of the attributes.
7164  */
7165  if (fkconstraint->pk_attrs == NIL)
7166  {
7167  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
7168  &fkconstraint->pk_attrs,
7169  pkattnum, pktypoid,
7170  opclasses);
7171  }
7172  else
7173  {
7174  numpks = transformColumnNameList(RelationGetRelid(pkrel),
7175  fkconstraint->pk_attrs,
7176  pkattnum, pktypoid);
7177  /* Look for an index matching the column list */
7178  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
7179  opclasses);
7180  }
7181 
7182  /*
7183  * Now we can check permissions.
7184  */
7185  checkFkeyPermissions(pkrel, pkattnum, numpks);
7186 
7187  /*
7188  * Look up the equality operators to use in the constraint.
7189  *
7190  * Note that we have to be careful about the difference between the actual
7191  * PK column type and the opclass' declared input type, which might be
7192  * only binary-compatible with it. The declared opcintype is the right
7193  * thing to probe pg_amop with.
7194  */
7195  if (numfks != numpks)
7196  ereport(ERROR,
7197  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
7198  errmsg("number of referencing and referenced columns for foreign key disagree")));
7199 
7200  /*
7201  * On the strength of a previous constraint, we might avoid scanning
7202  * tables to validate this one. See below.
7203  */
7204  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
7205  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
7206 
7207  for (i = 0; i < numpks; i++)
7208  {
7209  Oid pktype = pktypoid[i];
7210  Oid fktype = fktypoid[i];
7211  Oid fktyped;
7212  HeapTuple cla_ht;
7213  Form_pg_opclass cla_tup;
7214  Oid amid;
7215  Oid opfamily;
7216  Oid opcintype;
7217  Oid pfeqop;
7218  Oid ppeqop;
7219  Oid ffeqop;
7220  int16 eqstrategy;
7221  Oid pfeqop_right;
7222 
7223  /* We need several fields out of the pg_opclass entry */
7224  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
7225  if (!HeapTupleIsValid(cla_ht))
7226  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
7227  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
7228  amid = cla_tup->opcmethod;
7229  opfamily = cla_tup->opcfamily;
7230  opcintype = cla_tup->opcintype;
7231  ReleaseSysCache(cla_ht);
7232 
7233  /*
7234  * Check it's a btree; currently this can never fail since no other
7235  * index AMs support unique indexes. If we ever did have other types
7236  * of unique indexes, we'd need a way to determine which operator
7237  * strategy number is equality. (Is it reasonable to insist that
7238  * every such index AM use btree's number for equality?)
7239  */
7240  if (amid != BTREE_AM_OID)
7241  elog(ERROR, "only b-tree indexes are supported for foreign keys");
7242  eqstrategy = BTEqualStrategyNumber;
7243 
7244  /*
7245  * There had better be a primary equality operator for the index.
7246  * We'll use it for PK = PK comparisons.
7247  */
7248  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
7249  eqstrategy);
7250 
7251  if (!OidIsValid(ppeqop))
7252  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
7253  eqstrategy, opcintype, opcintype, opfamily);
7254 
7255  /*
7256  * Are there equality operators that take exactly the FK type? Assume
7257  * we should look through any domain here.
7258  */
7259  fktyped = getBaseType(fktype);
7260 
7261  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
7262  eqstrategy);
7263  if (OidIsValid(pfeqop))
7264  {
7265  pfeqop_right = fktyped;
7266  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
7267  eqstrategy);
7268  }
7269  else
7270  {
7271  /* keep compiler quiet */
7272  pfeqop_right = InvalidOid;
7273  ffeqop = InvalidOid;
7274  }
7275 
7276  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
7277  {
7278  /*
7279  * Otherwise, look for an implicit cast from the FK type to the
7280  * opcintype, and if found, use the primary equality operator.
7281  * This is a bit tricky because opcintype might be a polymorphic
7282  * type such as ANYARRAY or ANYENUM; so what we have to test is
7283  * whether the two actual column types can be concurrently cast to
7284  * that type. (Otherwise, we'd fail to reject combinations such
7285  * as int[] and point[].)
7286  */
7287  Oid input_typeids[2];
7288  Oid target_typeids[2];
7289 
7290  input_typeids[0] = pktype;
7291  input_typeids[1] = fktype;
7292  target_typeids[0] = opcintype;
7293  target_typeids[1] = opcintype;
7294  if (can_coerce_type(2, input_typeids, target_typeids,
7296  {
7297  pfeqop = ffeqop = ppeqop;
7298  pfeqop_right = opcintype;
7299  }
7300  }
7301 
7302  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
7303  ereport(ERROR,
7304  (errcode(ERRCODE_DATATYPE_MISMATCH),
7305  errmsg("foreign key constraint \"%s\" "
7306  "cannot be implemented",
7307  fkconstraint->conname),
7308  errdetail("Key columns \"%s\" and \"%s\" "
7309  "are of incompatible types: %s and %s.",
7310  strVal(list_nth(fkconstraint->fk_attrs, i)),
7311  strVal(list_nth(fkconstraint->pk_attrs, i)),
7312  format_type_be(fktype),
7313  format_type_be(pktype))));
7314 
7315  if (old_check_ok)
7316  {
7317  /*
7318  * When a pfeqop changes, revalidate the constraint. We could
7319  * permit intra-opfamily changes, but that adds subtle complexity
7320  * without any concrete benefit for core types. We need not
7321  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
7322  */
7323  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
7324  old_pfeqop_item = lnext(old_pfeqop_item);
7325  }
7326  if (old_check_ok)
7327  {
7328  Oid old_fktype;
7329  Oid new_fktype;
7330  CoercionPathType old_pathtype;
7331  CoercionPathType new_pathtype;
7332  Oid old_castfunc;
7333  Oid new_castfunc;
7335  fkattnum[i] - 1);
7336 
7337  /*
7338  * Identify coercion pathways from each of the old and new FK-side
7339  * column types to the right (foreign) operand type of the pfeqop.
7340  * We may assume that pg_constraint.conkey is not changing.
7341  */
7342  old_fktype = attr->atttypid;
7343  new_fktype = fktype;
7344  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
7345  &old_castfunc);
7346  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
7347  &new_castfunc);
7348 
7349  /*
7350  * Upon a change to the cast from the FK column to its pfeqop
7351  * operand, revalidate the constraint. For this evaluation, a
7352  * binary coercion cast is equivalent to no cast at all. While
7353  * type implementors should design implicit casts with an eye
7354  * toward consistency of operations like equality, we cannot
7355  * assume here that they have done so.
7356  *
7357  * A function with a polymorphic argument could change behavior
7358  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
7359  * when the cast destination is polymorphic, we only avoid
7360  * revalidation if the input type has not changed at all. Given
7361  * just the core data types and operator classes, this requirement
7362  * prevents no would-be optimizations.
7363  *
7364  * If the cast converts from a base type to a domain thereon, then
7365  * that domain type must be the opcintype of the unique index.
7366  * Necessarily, the primary key column must then be of the domain
7367  * type. Since the constraint was previously valid, all values on
7368  * the foreign side necessarily exist on the primary side and in
7369  * turn conform to the domain. Consequently, we need not treat
7370  * domains specially here.
7371  *
7372  * Since we require that all collations share the same notion of
7373  * equality (which they do, because texteq reduces to bitwise
7374  * equality), we don't compare collation here.
7375  *
7376  * We need not directly consider the PK type. It's necessarily
7377  * binary coercible to the opcintype of the unique index column,
7378  * and ri_triggers.c will only deal with PK datums in terms of
7379  * that opcintype. Changing the opcintype also changes pfeqop.
7380  */
7381  old_check_ok = (new_pathtype == old_pathtype &&
7382  new_castfunc == old_castfunc &&
7383  (!IsPolymorphicType(pfeqop_right) ||
7384  new_fktype == old_fktype));
7385 
7386  }
7387 
7388  pfeqoperators[i] = pfeqop;
7389  ppeqoperators[i] = ppeqop;
7390  ffeqoperators[i] = ffeqop;
7391  }
7392 
7393  /*
7394  * Record the FK constraint in pg_constraint.
7395  */
7396  constrOid = CreateConstraintEntry(fkconstraint->conname,
7397  RelationGetNamespace(rel),
7399  fkconstraint->deferrable,
7400  fkconstraint->initdeferred,
7401  fkconstraint->initially_valid,
7402  RelationGetRelid(rel),
7403  fkattnum,
7404  numfks,
7405  InvalidOid, /* not a domain constraint */
7406  indexOid,
7407  RelationGetRelid(pkrel),
7408  pkattnum,
7409  pfeqoperators,
7410  ppeqoperators,
7411  ffeqoperators,
7412  numpks,
7413  fkconstraint->fk_upd_action,
7414  fkconstraint->fk_del_action,
7415  fkconstraint->fk_matchtype,
7416  NULL, /* no exclusion constraint */
7417  NULL, /* no check constraint */
7418  NULL,
7419  NULL,
7420  true, /* islocal */
7421  0, /* inhcount */
7422  true, /* isnoinherit */
7423  false); /* is_internal */
7424  ObjectAddressSet(address, ConstraintRelationId, constrOid);
7425 
7426  /*
7427  * Create the triggers that will enforce the constraint.
7428  */
7429  createForeignKeyTriggers(rel, RelationGetRelid(pkrel), fkconstraint,
7430  constrOid, indexOid);
7431 
7432  /*
7433  * Tell Phase 3 to check that the constraint is satisfied by existing
7434  * rows. We can skip this during table creation, when requested explicitly
7435  * by specifying NOT VALID in an ADD FOREIGN KEY command, and when we're
7436  * recreating a constraint following a SET DATA TYPE operation that did
7437  * not impugn its validity.
7438  */
7439  if (!old_check_ok && !fkconstraint->skip_validation)
7440  {
7441  NewConstraint *newcon;
7442 
7443  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
7444  newcon->name = fkconstraint->conname;
7445  newcon->contype = CONSTR_FOREIGN;
7446  newcon->refrelid = RelationGetRelid(pkrel);
7447  newcon->refindid = indexOid;
7448  newcon->conid = constrOid;
7449  newcon->qual = (Node *) fkconstraint;
7450 
7451  tab->constraints = lappend(tab->constraints, newcon);
7452  }
7453 
7454  /*
7455  * Close pk table, but keep lock until we've committed.
7456  */
7457  heap_close(pkrel, NoLock);
7458 
7459  return address;
7460 }
signed short int16
Definition: c.h:293
#define NIL
Definition: pg_list.h:69
#define CONSTRAINT_FOREIGN
char * name
Definition: tablecmds.c:184
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
List * old_conpfeqop
Definition: parsenodes.h:2127
bool IsSystemRelation(Relation relation)
Definition: catalog.c:63
#define RELPERSISTENCE_UNLOGGED
Definition: pg_class.h:171
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
char fk_matchtype
Definition: parsenodes.h:2124
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids)
Definition: tablecmds.c:7810
#define BTREE_AM_OID
Definition: pg_am.h:70
bool rd_islocaltemp
Definition: rel.h:90
Node * qual
Definition: tablecmds.c:189
Definition: nodes.h:512
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
bool initdeferred
Definition: parsenodes.h:2097
#define MemSet(start, val, len)
Definition: c.h:877
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
#define heap_close(r, l)
Definition: heapam.h:97
List * pk_attrs
Definition: parsenodes.h:2123
char * conname
Definition: parsenodes.h:2095
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:8122
#define OidIsValid(objectId)
Definition: c.h:586
CoercionPathType
Definition: parse_coerce.h:24
List * constraints
Definition: tablecmds.c:163
#define RELPERSISTENCE_PERMANENT
Definition: pg_class.h:170
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define IsPolymorphicType(typid)
Definition: pg_type.h:745
bool deferrable
Definition: parsenodes.h:2096
TupleDesc oldDesc
Definition: tablecmds.c:159
void * list_nth(const List *list, int n)
Definition: list.c:410
#define NoLock
Definition: lockdefs.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:873
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
#define RelationGetRelationName(relation)
Definition: rel.h:445
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
static void createForeignKeyTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:8369
#define lnext(lc)
Definition: pg_list.h:105
#define ereport(elevel, rest)
Definition: elog.h:122
Oid old_pktable_oid
Definition: parsenodes.h:2128
List * lappend(List *list, void *datum)
Definition: list.c:128
ConstrType contype
Definition: tablecmds.c:185
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
void * palloc0(Size size)
Definition: mcxt.c:864
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1318
bool allowSystemTableMods
Definition: globals.c:112
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2133
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
Definition: tablecmds.c:7855
char fk_del_action
Definition: parsenodes.h:2126
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:680
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:8093
#define INDEX_MAX_KEYS
static int list_length(const List *l)
Definition: pg_list.h:89
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
Definition: tablecmds.c:7952
bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, CoercionContext ccontext)
Definition: parse_coerce.c:543
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:219
#define RELPERSISTENCE_TEMP
Definition: pg_class.h:172
RangeVar * pktable
Definition: parsenodes.h:2121
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2290
#define RELKIND_RELATION
Definition: pg_class.h:160
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
bool skip_validation
Definition: parsenodes.h:2132
#define RelationGetRelid(relation)
Definition: rel.h:425
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid relId, const int16 *constraintKey, int constraintNKeys, 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, const char *conSrc, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:49
List * fk_attrs
Definition: parsenodes.h:2122
#define BTEqualStrategyNumber
Definition: stratnum.h:31
char fk_upd_action
Definition: parsenodes.h:2125
#define lfirst_oid(lc)
Definition: pg_list.h:108
#define RelationGetNamespace(relation)
Definition: rel.h:452

◆ ATColumnChangeRequiresRewrite()

static bool ATColumnChangeRequiresRewrite ( Node expr,
AttrNumber  varattno 
)
static

Definition at line 8978 of file tablecmds.c.

References arg, CoerceToDomain::arg, Assert, DomainHasConstraints(), IsA, and CoerceToDomain::resulttype.

Referenced by ATPrepAlterColumnType().

8979 {
8980  Assert(expr != NULL);
8981 
8982  for (;;)
8983  {
8984  /* only one varno, so no need to check that */
8985  if (IsA(expr, Var) &&((Var *) expr)->varattno == varattno)
8986  return false;
8987  else if (IsA(expr, RelabelType))
8988  expr = (Node *) ((RelabelType *) expr)->arg;
8989  else if (IsA(expr, CoerceToDomain))
8990  {
8991  CoerceToDomain *d = (CoerceToDomain *) expr;
8992 
8994  return true;
8995  expr = (Node *) d->arg;
8996  }
8997  else
8998  return true;
8999  }
9000 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
Definition: nodes.h:512
Definition: primnodes.h:163
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1268
#define Assert(condition)
Definition: c.h:680
void * arg

◆ ATController()

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

Definition at line 3459 of file tablecmds.c.

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

Referenced by AlterTable(), and AlterTableInternal().

3461 {
3462  List *wqueue = NIL;
3463  ListCell *lcmd;
3464 
3465  /* Phase 1: preliminary examination of commands, create work queue */
3466  foreach(lcmd, cmds)
3467  {
3468  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3469 
3470  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode);
3471  }
3472 
3473  /* Close the relation, but keep lock until commit */
3474  relation_close(rel, NoLock);
3475 
3476  /* Phase 2: update system catalogs */
3477  ATRewriteCatalogs(&wqueue, lockmode);
3478 
3479  /* Phase 3: scan/rewrite tables as needed */
3480  ATRewriteTables(parsetree, &wqueue, lockmode);
3481 }
#define NIL
Definition: pg_list.h:69
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
#define NoLock
Definition: lockdefs.h:34
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
Definition: tablecmds.c:4142
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:3493
#define lfirst(lc)
Definition: pg_list.h:106
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode)
Definition: tablecmds.c:3792
Definition: pg_list.h:45

◆ AtEOSubXact_on_commit_actions()

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

Definition at line 13034 of file tablecmds.c.

References OnCommitItem::creating_subid, OnCommitItem::deleting_subid, InvalidSubTransactionId, lfirst, list_delete_cell(), list_head(), lnext, and pfree().

Referenced by AbortSubTransaction(), and CommitSubTransaction().

13036 {
13037  ListCell *cur_item;
13038  ListCell *prev_item;
13039 
13040  prev_item = NULL;
13041  cur_item = list_head(on_commits);
13042 
13043  while (cur_item != NULL)
13044  {
13045  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
13046 
13047  if (!isCommit && oc->creating_subid == mySubid)
13048  {
13049  /* cur_item must be removed */
13050  on_commits = list_delete_cell(on_commits, cur_item, prev_item);
13051  pfree(oc);
13052  if (prev_item)
13053  cur_item = lnext(prev_item);
13054  else
13055  cur_item = list_head(on_commits);
13056  }
13057  else
13058  {
13059  /* cur_item must be preserved */
13060  if (oc->creating_subid == mySubid)
13061  oc->creating_subid = parentSubid;
13062  if (oc->deleting_subid == mySubid)
13063  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
13064  prev_item = cur_item;
13065  cur_item = lnext(prev_item);
13066  }
13067  }
13068 }
SubTransactionId creating_subid
Definition: tablecmds.c:120
void pfree(void *pointer)
Definition: mcxt.c:936
static List * on_commits
Definition: tablecmds.c:124
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
List * list_delete_cell(List *list, ListCell *cell, ListCell *prev)
Definition: list.c:528
SubTransactionId deleting_subid
Definition: tablecmds.c:121
#define lfirst(lc)
Definition: pg_list.h:106
#define InvalidSubTransactionId
Definition: c.h:461

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 12992 of file tablecmds.c.

References OnCommitItem::creating_subid, OnCommitItem::deleting_subid, InvalidSubTransactionId, lfirst, list_delete_cell(), list_head(), lnext, and pfree().

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

12993 {
12994  ListCell *cur_item;
12995  ListCell *prev_item;
12996 
12997  prev_item = NULL;
12998  cur_item = list_head(on_commits);
12999 
13000  while (cur_item != NULL)
13001  {
13002  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
13003 
13004  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
13006  {
13007  /* cur_item must be removed */
13008  on_commits = list_delete_cell(on_commits, cur_item, prev_item);
13009  pfree(oc);
13010  if (prev_item)
13011  cur_item = lnext(prev_item);
13012  else
13013  cur_item = list_head(on_commits);
13014  }
13015  else
13016  {
13017  /* cur_item must be preserved */
13020  prev_item = cur_item;
13021  cur_item = lnext(prev_item);
13022  }
13023  }
13024 }
SubTransactionId creating_subid
Definition: tablecmds.c:120
void pfree(void *pointer)
Definition: mcxt.c:936
static List * on_commits
Definition: tablecmds.c:124
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
List * list_delete_cell(List *list, ListCell *cell, ListCell *prev)
Definition: list.c:528
SubTransactionId deleting_subid
Definition: tablecmds.c:121
#define lfirst(lc)
Definition: pg_list.h:106
#define InvalidSubTransactionId
Definition: c.h:461

◆ ATExecAddColumn()

static ObjectAddress ATExecAddColumn ( List **  wqueue,
AlteredTableInfo tab,
Relation  rel,
ColumnDef colDef,
bool  isOid,
bool  recurse,
bool  recursing,
bool  if_not_exists,
LOCKMODE  lockmode 
)
static

Definition at line 5171 of file tablecmds.c.

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, add_column_collation_dependency(), add_column_datatype_dependency(), AddRelationNewConstraints(), TypeName::arrayBounds, AT_REWRITE_ALTER_OID, AT_REWRITE_DEFAULT_VAL, ATGetQueueEntry(), ATSimplePermissions(), ATT_FOREIGN_TABLE, ATT_TABLE, RawColumnDefault::attnum, NewColumnValue::attnum, AttributeRelationId, build_column_default(), CatalogTupleUpdate(), check_for_column_name_collision(), CheckAttributeType(), CheckTableNotInUse(), COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, ColumnDef::colname, CommandCounterIncrement(), copyObject, DomainHasConstraints(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, NewColumnValue::expr, expression_planner(), find_inheritance_children(), FormData_pg_attribute, get_collation_name(), get_typcollation(), getBaseTypeAndTypmod(), GetColumnDefCollation(), GETSTRUCT, GetUserId(), heap_close, heap_freetuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, ColumnDef::identity, ColumnDef::inhcount, InsertPgAttributeTuple(), InvalidObjectAddress, InvokeObjectPostCreateHook, ColumnDef::is_local, ColumnDef::is_not_null, lappend(), lfirst_oid, list_length(), list_make1, list_make1_oid, makeNullConst(), MaxHeapAttributeNumber, namestrcpy(), AlteredTableInfo::new_notnull, newval, AlteredTableInfo::newvals, NIL, NoLock, NOTICE, ObjectAddressSubSet, ObjectIdAttributeNumber, ObjectIdGetDatum, palloc(), palloc0(), pg_type_aclcheck(), RawColumnDefault::raw_default, ColumnDef::raw_default, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, RelationRelationId, ReleaseSysCache(), DropRelationCallbackState::relkind, RELKIND_COMPOSITE_TYPE, RELKIND_FOREIGN_TABLE, RELKIND_VIEW, RELOID, AlteredTableInfo::rewrite, RowExclusiveLock, SearchSysCacheCopy1, SearchSysCacheCopyAttName(), HeapTupleData::t_self, ColumnDef::typeName, typenameType(), and typenameTypeIdAndMod().

Referenced by ATExecCmd().

5175 {
5176  Oid myrelid = RelationGetRelid(rel);
5177  Relation pgclass,
5178  attrdesc;
5179  HeapTuple reltup;
5180  FormData_pg_attribute attribute;
5181  int newattnum;
5182  char relkind;
5183  HeapTuple typeTuple;
5184  Oid typeOid;
5185  int32 typmod;
5186  Oid collOid;
5187  Form_pg_type tform;
5188  Expr *defval;
5189  List *children;
5190  ListCell *child;
5191  AclResult aclresult;
5192  ObjectAddress address;
5193 
5194  /* At top level, permission check was done in ATPrepCmd, else do it */
5195  if (recursing)
5197 
5198  if (rel->rd_rel->relispartition && !recursing)
5199  ereport(ERROR,
5200  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5201  errmsg("cannot add column to a partition")));
5202 
5204 
5205  /*
5206  * Are we adding the column to a recursion child? If so, check whether to
5207  * merge with an existing definition for the column. If we do merge, we
5208  * must not recurse. Children will already have the column, and recursing
5209  * into them would mess up attinhcount.
5210  */
5211  if (colDef->inhcount > 0)
5212  {
5213  HeapTuple tuple;
5214 
5215  /* Does child already have a column by this name? */
5216  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
5217  if (HeapTupleIsValid(tuple))
5218  {
5219  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
5220  Oid ctypeId;
5221  int32 ctypmod;
5222  Oid ccollid;
5223 
5224  /* Child column must match on type, typmod, and collation */
5225  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
5226  if (ctypeId != childatt->atttypid ||
5227  ctypmod != childatt->atttypmod)
5228  ereport(ERROR,
5229  (errcode(ERRCODE_DATATYPE_MISMATCH),
5230  errmsg("child table \"%s\" has different type for column \"%s\"",
5231  RelationGetRelationName(rel), colDef->colname)));
5232  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
5233  if (ccollid != childatt->attcollation)
5234  ereport(ERROR,
5235  (errcode(ERRCODE_COLLATION_MISMATCH),
5236  errmsg("child table \"%s\" has different collation for column \"%s\"",
5237  RelationGetRelationName(rel), colDef->colname),
5238  errdetail("\"%s\" versus \"%s\"",
5239  get_collation_name(ccollid),
5240  get_collation_name(childatt->attcollation))));
5241 
5242  /* If it's OID, child column must actually be OID */
5243  if (isOid && childatt->attnum != ObjectIdAttributeNumber)
5244  ereport(ERROR,
5245  (errcode(ERRCODE_DATATYPE_MISMATCH),
5246  errmsg("child table \"%s\" has a conflicting \"%s\" column",
5247  RelationGetRelationName(rel), colDef->colname)));
5248 
5249  /* Bump the existing child att's inhcount */
5250  childatt->attinhcount++;
5251  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
5252 
5253  heap_freetuple(tuple);
5254 
5255  /* Inform the user about the merge */
5256  ereport(NOTICE,
5257  (errmsg("merging definition of column \"%s\" for child \"%s\"",
5258  colDef->colname, RelationGetRelationName(rel))));
5259 
5260  heap_close(attrdesc, RowExclusiveLock);
5261  return InvalidObjectAddress;
5262  }
5263  }
5264 
5266 
5267  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
5268  if (!HeapTupleIsValid(reltup))
5269  elog(ERROR, "cache lookup failed for relation %u", myrelid);
5270  relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
5271 
5272  /*
5273  * Cannot add identity column if table has children, because identity does
5274  * not inherit. (Adding column and identity separately will work.)
5275  */
5276  if (colDef->identity &&
5277  recurse &&
5278  find_inheritance_children(myrelid, NoLock) != NIL)
5279  ereport(ERROR,
5280  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
5281  errmsg("cannot recursively add identity column to table that has child tables")));
5282 
5283  /* skip if the name already exists and if_not_exists is true */
5284  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
5285  {
5286  heap_close(attrdesc, RowExclusiveLock);
5287  heap_freetuple(reltup);
5288  heap_close(pgclass, RowExclusiveLock);
5289  return InvalidObjectAddress;
5290  }
5291 
5292  /* Determine the new attribute's number */
5293  if (isOid)
5294  newattnum = ObjectIdAttributeNumber;
5295  else
5296  {
5297  newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
5298  if (newattnum > MaxHeapAttributeNumber)
5299  ereport(ERROR,
5300  (errcode(ERRCODE_TOO_MANY_COLUMNS),
5301  errmsg("tables can have at most %d columns",
5303  }
5304 
5305  typeTuple = typenameType(NULL, colDef->typeName, &typmod);
5306  tform = (Form_pg_type) GETSTRUCT(typeTuple);
5307  typeOid = HeapTupleGetOid(typeTuple);
5308 
5309  aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
5310  if (aclresult != ACLCHECK_OK)
5311  aclcheck_error_type(aclresult, typeOid);
5312 
5313  collOid = GetColumnDefCollation(NULL, colDef, typeOid);
5314 
5315  /* make sure datatype is legal for a column */
5316  CheckAttributeType(colDef->colname, typeOid, collOid,
5317  list_make1_oid(rel->rd_rel->reltype),
5318  false);
5319 
5320  /* construct new attribute's pg_attribute entry */
5321  attribute.attrelid = myrelid;
5322  namestrcpy(&(attribute.attname), colDef->colname);
5323  attribute.atttypid = typeOid;
5324  attribute.attstattarget = (newattnum > 0) ? -1 : 0;
5325  attribute.attlen = tform->typlen;
5326  attribute.attcacheoff = -1;
5327  attribute.atttypmod = typmod;
5328  attribute.attnum = newattnum;
5329  attribute.attbyval = tform->typbyval;
5330  attribute.attndims = list_length(colDef->typeName->arrayBounds);
5331  attribute.attstorage = tform->typstorage;
5332  attribute.attalign = tform->typalign;
5333  attribute.attnotnull = colDef->is_not_null;
5334  attribute.atthasdef = false;
5335  attribute.attidentity = colDef->identity;
5336  attribute.attisdropped = false;
5337  attribute.attislocal = colDef->is_local;
5338  attribute.attinhcount = colDef->inhcount;
5339  attribute.attcollation = collOid;
5340  /* attribute.attacl is handled by InsertPgAttributeTuple */
5341 
5342  ReleaseSysCache(typeTuple);
5343 
5344  InsertPgAttributeTuple(attrdesc, &attribute, NULL);
5345 
5346  heap_close(attrdesc, RowExclusiveLock);
5347 
5348  /*
5349  * Update pg_class tuple as appropriate
5350  */
5351  if (isOid)
5352  ((Form_pg_class) GETSTRUCT(reltup))->relhasoids = true;
5353  else
5354  ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
5355 
5356  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
5357 
5358  heap_freetuple(reltup);
5359 
5360  /* Post creation hook for new attribute */
5361  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
5362 
5363  heap_close(pgclass, RowExclusiveLock);
5364 
5365  /* Make the attribute's catalog entry visible */
5367 
5368  /*
5369  * Store the DEFAULT, if any, in the catalogs
5370  */
5371  if (colDef->raw_default)
5372  {
5373  RawColumnDefault *rawEnt;
5374 
5375  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
5376  rawEnt->attnum = attribute.attnum;
5377  rawEnt->raw_default = copyObject(colDef->raw_default);
5378 
5379  /*
5380  * This function is intended for CREATE TABLE, so it processes a
5381  * _list_ of defaults, but we just do one.
5382  */
5384  false, true, false);
5385 
5386  /* Make the additional catalog changes visible */
5388  }
5389 
5390  /*
5391  * Tell Phase 3 to fill in the default expression, if there is one.
5392  *
5393  * If there is no default, Phase 3 doesn't have to do anything, because
5394  * that effectively means that the default is NULL. The heap tuple access
5395  * routines always check for attnum > # of attributes in tuple, and return
5396  * NULL if so, so without any modification of the tuple data we will get
5397  * the effect of NULL values in the new column.
5398  *
5399  * An exception occurs when the new column is of a domain type: the domain
5400  * might have a NOT NULL constraint, or a check constraint that indirectly
5401  * rejects nulls. If there are any domain constraints then we construct
5402  * an explicit NULL default value that will be passed through
5403  * CoerceToDomain processing. (This is a tad inefficient, since it causes
5404  * rewriting the table which we really don't have to do, but the present
5405  * design of domain processing doesn't offer any simple way of checking
5406  * the constraints more directly.)
5407  *
5408  * Note: we use build_column_default, and not just the cooked default
5409  * returned by AddRelationNewConstraints, so that the right thing happens
5410  * when a datatype's default applies.
5411  *
5412  * We skip this step completely for views and foreign tables. For a view,
5413  * we can only get here from CREATE OR REPLACE VIEW, which historically
5414  * doesn't set up defaults, not even for domain-typed columns. And in any
5415  * case we mustn't invoke Phase 3 on a view or foreign table, since they
5416  * have no storage.
5417  */
5418  if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE
5419  && relkind != RELKIND_FOREIGN_TABLE && attribute.attnum > 0)
5420  {
5421  defval = (Expr *) build_column_default(rel, attribute.attnum);
5422 
5423  if (!defval && DomainHasConstraints(typeOid))
5424  {
5425  Oid baseTypeId;
5426  int32 baseTypeMod;
5427  Oid baseTypeColl;
5428 
5429  baseTypeMod = typmod;
5430  baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
5431  baseTypeColl = get_typcollation(baseTypeId);
5432  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
5433  defval = (Expr *) coerce_to_target_type(NULL,
5434  (Node *) defval,
5435  baseTypeId,
5436  typeOid,
5437  typmod,
5440  -1);
5441  if (defval == NULL) /* should not happen */
5442  elog(ERROR, "failed to coerce base type to domain");
5443  }
5444 
5445  if (defval)
5446  {
5448 
5449  newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
5450  newval->attnum = attribute.attnum;
5451  newval->expr = expression_planner(defval);
5452 
5453  tab->newvals = lappend(tab->newvals, newval);
5455  }
5456 
5457  /*
5458  * If the new column is NOT NULL, tell Phase 3 it needs to test that.
5459  * (Note we don't do this for an OID column. OID will be marked not
5460  * null, but since it's filled specially, there's no need to test
5461  * anything.)
5462  */
5463  tab->new_notnull |= colDef->is_not_null;
5464  }
5465 
5466  /*
5467  * If we are adding an OID column, we have to tell Phase 3 to rewrite the
5468  * table to fix that.
5469  */
5470  if (isOid)
5471  tab->rewrite |= AT_REWRITE_ALTER_OID;
5472 
5473  /*
5474  * Add needed dependency entries for the new column.
5475  */
5476  add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
5477  add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
5478 
5479  /*
5480  * Propagate to children as appropriate. Unlike most other ALTER
5481  * routines, we have to do this one level of recursion at a time; we can't
5482  * use find_all_inheritors to do it in one pass.
5483  */
5484  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
5485 
5486  /*
5487  * If we are told not to recurse, there had better not be any child
5488  * tables; else the addition would put them out of step.
5489  */
5490  if (children && !recurse)
5491  ereport(ERROR,
5492  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
5493  errmsg("column must be added to child tables too")));
5494 
5495  /* Children should see column as singly inherited */
5496  if (!recursing)
5497  {
5498  colDef = copyObject(colDef);
5499  colDef->inhcount = 1;
5500  colDef->is_local = false;
5501  }
5502 
5503  foreach(child, children)
5504  {
5505  Oid childrelid = lfirst_oid(child);
5506  Relation childrel;
5507  AlteredTableInfo *childtab;
5508 
5509  /* find_inheritance_children already got lock */
5510  childrel = heap_open(childrelid, NoLock);
5511  CheckTableNotInUse(childrel, "ALTER TABLE");
5512 
5513  /* Find or create work queue entry for this table */
5514  childtab = ATGetQueueEntry(wqueue, childrel);
5515 
5516  /* Recurse to child; return value is ignored */
5517  ATExecAddColumn(wqueue, childtab, childrel,
5518  colDef, isOid, recurse, true,
5519  if_not_exists, lockmode);
5520 
5521  heap_close(childrel, NoLock);
5522  }
5523 
5524  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
5525  return address;
5526 }
#define NIL
Definition: pg_list.h:69
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2307
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:247
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
AttrNumber attnum
Definition: heap.h:24
bool is_local
Definition: parsenodes.h:642
Oid GetUserId(void)
Definition: miscinit.c:284
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
char identity
Definition: parsenodes.h:649
char * get_collation_name(Oid colloid)
Definition: lsyscache.c:967
#define RelationRelationId
Definition: pg_class.h:29
Expr * expression_planner(Expr *expr)
Definition: planner.c:6026
static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, ColumnDef *colDef, bool isOid, bool recurse, bool recursing, bool if_not_exists, LOCKMODE lockmode)
Definition: tablecmds.c:5171
Definition: nodes.h:512
#define AttributeRelationId
Definition: pg_attribute.h:33
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
bool is_not_null
Definition: parsenodes.h:643
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
#define ATT_TABLE
Definition: tablecmds.c:281
int namestrcpy(Name name, const char *str)
Definition: name.c:216
#define RELKIND_COMPOSITE_TYPE
Definition: pg_class.h:166
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3515
signed int int32
Definition: c.h:294
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:336
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1268
#define list_make1(x1)
Definition: pg_list.h:139
#define AT_REWRITE_DEFAULT_VAL
Definition: event_trigger.h:32
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid)
Definition: tablecmds.c:5586
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:1271
ItemPointerData t_self
Definition: htup.h:65
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:5604
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define RelationGetRelationName(relation)
Definition: rel.h:445
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:4699
Node * raw_default
Definition: heap.h:25
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define ACL_USAGE
Definition: parsenodes.h:80
#define AT_REWRITE_ALTER_OID
Definition: event_trigger.h:34
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3062
#define ereport(elevel, rest)
Definition: elog.h:122
Node * raw_default
Definition: parsenodes.h:647
List * lappend(List *list, void *datum)
Definition: list.c:128
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, bool allow_system_table_mods)
Definition: heap.c:490
Oid GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid)
Definition: parse_type.c:521
Node * build_column_default(Relation rel, int attrno)
void * palloc0(Size size)
Definition: mcxt.c:864
AclResult
Definition: acl.h:178
void CommandCounterIncrement(void)
Definition: xact.c:915
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define list_make1_oid(x1)
Definition: pg_list.h:151
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, Oid *typeid_p, int32 *typmod_p)
Definition: parse_type.c:293
FormData_pg_attribute
Definition: pg_attribute.h:171
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:57
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:2814
#define NOTICE
Definition: elog.h:37
#define MaxHeapAttributeNumber
Definition: htup_details.h:47
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
static int list_length(const List *l)
Definition: pg_list.h:89
#define newval
TypeName * typeName
Definition: parsenodes.h:640
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
List * arrayBounds
Definition: parsenodes.h:214
void InsertPgAttributeTuple(Relation pg_attribute_rel, Form_pg_attribute new_attribute, CatalogIndexState indstate)
Definition: heap.c:600
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:835
int errmsg(const char *fmt,...)
Definition: elog.c:797
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:5533
#define RELKIND_VIEW
Definition: pg_class.h:164
int inhcount
Definition: parsenodes.h:641
static void ATSimplePermissions(Relation rel, int allowed_targets)
Definition: tablecmds.c:4736
char * colname
Definition: parsenodes.h:639
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:700
#define copyObject(obj)
Definition: nodes.h:625
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4592
Definition: pg_list.h:45
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:286
#define RelationGetRelid(relation)
Definition: rel.h:425
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal)
Definition: heap.c:2229
#define lfirst_oid(lc)
Definition: pg_list.h:108
AttrNumber attnum
Definition: tablecmds.c:202

◆ ATExecAddConstraint()

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

Definition at line 6850 of file tablecmds.c.

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

Referenced by ATExecCmd().

6853 {
6855 
6856  Assert(IsA(newConstraint, Constraint));
6857 
6858  /*
6859  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
6860  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
6861  * switch anyway to make it easier to add more code later.
6862  */
6863  switch (newConstraint->contype)
6864  {
6865  case CONSTR_CHECK:
6866  address =
6867  ATAddCheckConstraint(wqueue, tab, rel,
6868  newConstraint, recurse, false, is_readd,
6869  lockmode);
6870  break;
6871 
6872  case CONSTR_FOREIGN:
6873 
6874  /*
6875  * Note that we currently never recurse for FK constraints, so the
6876  * "recurse" flag is silently ignored.
6877  *
6878  * Assign or validate constraint name
6879  */
6880  if (newConstraint->conname)
6881  {
6883  RelationGetRelid(rel),
6884  RelationGetNamespace(rel),
6885  newConstraint->conname))
6886  ereport(ERROR,
6888  errmsg("constraint \"%s\" for relation \"%s\" already exists",
6889  newConstraint->conname,
6890  RelationGetRelationName(rel))));
6891  }
6892  else
6893  newConstraint->conname =
6895  strVal(linitial(newConstraint->fk_attrs)),
6896  "fkey",
6897  RelationGetNamespace(rel),
6898  NIL);
6899 
6900  address = ATAddForeignKeyConstraint(tab, rel, newConstraint,
6901  lockmode);
6902  break;
6903 
6904  default:
6905  elog(ERROR, "unrecognized constraint type: %d",
6906  (int) newConstraint->contype);
6907  }
6908 
6909  return address;
6910 }
#define NIL
Definition: pg_list.h:69
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
static ObjectAddress ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, LOCKMODE lockmode)
Definition: tablecmds.c:7055
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:6928
char * conname
Definition: parsenodes.h:2095
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:445
#define ereport(elevel, rest)
Definition: elog.h:122
#define Assert(condition)
Definition: c.h:680
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, Oid objNamespace, const char *conname)
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
ConstrType contype
Definition: parsenodes.h:2092
#define elog
Definition: elog.h:219
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
#define RelationGetRelid(relation)
Definition: rel.h:425
List * fk_attrs
Definition: parsenodes.h:2122
#define RelationGetNamespace(relation)
Definition: rel.h:452

◆ ATExecAddIdentity()

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

Definition at line 5958 of file tablecmds.c.

References AttributeRelationId, castNode, CatalogTupleUpdate(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_close, heap_freetuple(), heap_open(), HeapTupleIsValid, ColumnDef::identity, InvokeObjectPostAlterHook, ObjectAddressSubSet, RelationGetRelationName, RelationGetRelid, RelationRelationId, RowExclusiveLock, SearchSysCacheCopyAttName(), and HeapTupleData::t_self.

Referenced by ATExecCmd().

5960 {
5961  Relation attrelation;
5962  HeapTuple tuple;
5963  Form_pg_attribute attTup;
5964  AttrNumber attnum;
5965  ObjectAddress address;
5966  ColumnDef *cdef = castNode(ColumnDef, def);
5967 
5969 
5970  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
5971  if (!HeapTupleIsValid(tuple))
5972  ereport(ERROR,
5973  (errcode(ERRCODE_UNDEFINED_COLUMN),
5974  errmsg("column \"%s\" of relation \"%s\" does not exist",
5975  colName, RelationGetRelationName(rel))));
5976  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
5977  attnum = attTup->attnum;
5978 
5979  /* Can't alter a system attribute */
5980  if (attnum <= 0)
5981  ereport(ERROR,
5982  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5983  errmsg("cannot alter system column \"%s\"",
5984  colName)));
5985 
5986  /*
5987  * Creating a column as identity implies NOT NULL, so adding the identity
5988  * to an existing column that is not NOT NULL would create a state that
5989  * cannot be reproduced without contortions.
5990  */
5991  if (!attTup->attnotnull)
5992  ereport(ERROR,
5993  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
5994  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
5995  colName, RelationGetRelationName(rel))));
5996 
5997  if (attTup->attidentity)
5998  ereport(ERROR,
5999  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
6000  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
6001  colName, RelationGetRelationName(rel))));
6002 
6003  if (attTup->atthasdef)
6004  ereport(ERROR,
6005  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
6006  errmsg("column \"%s\" of relation \"%s\" already has a default value",
6007  colName, RelationGetRelationName(rel))));
6008 
6009  attTup->attidentity = cdef->identity;
6010  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
6011 
6013  RelationGetRelid(rel),
6014  attTup->attnum);
6016  RelationGetRelid(rel), attnum);
6017  heap_freetuple(tuple);
6018 
6019  heap_close(attrelation, RowExclusiveLock);
6020 
6021  return address;
6022 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define castNode(_type_, nodeptr)
Definition: nodes.h:581
char identity
Definition: parsenodes.h:649
#define RelationRelationId
Definition: pg_class.h:29
#define AttributeRelationId
Definition: pg_attribute.h:33
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:1271
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:445
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
int errmsg(const char *fmt,...)
Definition: elog.c:797
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:425

◆ ATExecAddIndex()

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

Definition at line 6715 of file tablecmds.c.

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

Referenced by ATExecCmd().

6717 {
6718  bool check_rights;
6719  bool skip_build;
6720  bool quiet;
6721  ObjectAddress address;
6722 
6723  Assert(IsA(stmt, IndexStmt));
6724  Assert(!stmt->concurrent);
6725 
6726  /* The IndexStmt has already been through transformIndexStmt */
6727  Assert(stmt->transformed);
6728 
6729  /* suppress schema rights check when rebuilding existing index */
6730  check_rights = !is_rebuild;
6731  /* skip index build if phase 3 will do it or we're reusing an old one */
6732  skip_build = tab->rewrite > 0 || OidIsValid(stmt->oldNode);
6733  /* suppress notices when rebuilding existing index */
6734  quiet = is_rebuild;
6735 
6736  address = DefineIndex(RelationGetRelid(rel),
6737  stmt,
6738  InvalidOid, /* no predefined OID */
6739  true, /* is_alter_table */
6740  check_rights,
6741  false, /* check_not_in_use - we did it already */
6742  skip_build,
6743  quiet);
6744 
6745  /*
6746  * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
6747  * index instead of building from scratch. The DROP of the old edition of
6748  * this index will have scheduled the storage for deletion at commit, so
6749  * cancel that pending deletion.
6750  */
6751  if (OidIsValid(stmt->oldNode))
6752  {
6753  Relation irel = index_open(address.objectId, NoLock);
6754 
6755  RelationPreserveStorage(irel->rd_node, true);
6756  index_close(irel, NoLock);
6757  }
6758 
6759  return address;
6760 }
void RelationPreserveStorage(RelFileNode rnode, bool atCommit)
Definition: storage.c:190
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
#define OidIsValid(objectId)
Definition: c.h:586
#define NoLock
Definition: lockdefs.h:34
bool transformed
Definition: parsenodes.h:2726
#define InvalidOid
Definition: postgres_ext.h:36
RelFileNode rd_node
Definition: rel.h:85
#define Assert(condition)
Definition: c.h:680
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
bool concurrent
Definition: parsenodes.h:2727
ObjectAddress DefineIndex(Oid relationId, IndexStmt *stmt, Oid indexRelationId, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition: indexcmds.c:308
#define RelationGetRelid(relation)
Definition: rel.h:425
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151

◆ ATExecAddIndexConstraint()

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

Definition at line 6768 of file tablecmds.c.

References AccessShareLock, allowSystemTableMods, Assert, BuildIndexInfo(), CONSTRAINT_PRIMARY, CONSTRAINT_UNIQUE, IndexStmt::deferrable, elog, ereport, 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, IsA, IndexStmt::isconstraint, NoLock, NOTICE, OidIsValid, IndexStmt::primary, pstrdup(), RelationGetRelationName, and RenameRelationInternal().

Referenced by ATExecCmd().

6770 {
6771  Oid index_oid = stmt->indexOid;
6772  Relation indexRel;
6773  char *indexName;
6774  IndexInfo *indexInfo;
6775  char *constraintName;
6776  char constraintType;
6777  ObjectAddress address;
6778  bits16 flags;
6779 
6780  Assert(IsA(stmt, IndexStmt));
6781  Assert(OidIsValid(index_oid));
6782  Assert(stmt->isconstraint);
6783 
6784  indexRel = index_open(index_oid, AccessShareLock);
6785 
6786  indexName = pstrdup(RelationGetRelationName(indexRel));
6787 
6788  indexInfo = BuildIndexInfo(indexRel);
6789 
6790  /* this should have been checked at parse time */
6791  if (!indexInfo->ii_Unique)
6792  elog(ERROR, "index \"%s\" is not unique", indexName);
6793 
6794  /*
6795  * Determine name to assign to constraint. We require a constraint to
6796  * have the same name as the underlying index; therefore, use the index's
6797  * existing name as the default constraint name, and if the user
6798  * explicitly gives some other name for the constraint, rename the index
6799  * to match.
6800  */
6801  constraintName = stmt->idxname;
6802  if (constraintName == NULL)
6803  constraintName = indexName;
6804  else if (strcmp(constraintName, indexName) != 0)
6805  {
6806  ereport(NOTICE,
6807  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
6808  indexName, constraintName)));
6809  RenameRelationInternal(index_oid, constraintName, false);
6810  }
6811 
6812  /* Extra checks needed if making primary key */
6813  if (stmt->primary)
6814  index_check_primary_key(rel, indexInfo, true);
6815 
6816  /* Note we currently don't support EXCLUSION constraints here */
6817  if (stmt->primary)
6818  constraintType = CONSTRAINT_PRIMARY;
6819  else
6820  constraintType = CONSTRAINT_UNIQUE;
6821 
6822  /* Create the catalog entries for the constraint */
6828 
6829  address = index_constraint_create(rel,
6830  index_oid,
6831  indexInfo,
6832  constraintName,
6833  constraintType,
6834  flags,
6836  false); /* is_internal */
6837 
6838  index_close(indexRel, NoLock);
6839 
6840  return address;
6841 }
bool deferrable
Definition: parsenodes.h:2724
bool primary
Definition: parsenodes.h:2722
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
Definition: tablecmds.c:2966
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
uint16 bits16
Definition: c.h:314
char * pstrdup(const char *in)
Definition: mcxt.c:1063
#define AccessShareLock
Definition: lockdefs.h:36
void index_check_primary_key(Relation heapRel, IndexInfo *indexInfo, bool is_alter_table)
Definition: index.c:195
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:1645
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:72
unsigned int Oid
Definition: postgres_ext.h:31
#define CONSTRAINT_UNIQUE
#define OidIsValid(objectId)
Definition: c.h:586
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:70
#define CONSTRAINT_PRIMARY
Oid indexOid
Definition: parsenodes.h:2719
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:445
#define ereport(elevel, rest)
Definition: elog.h:122
char * idxname
Definition: parsenodes.h:2710
bool allowSystemTableMods
Definition: globals.c:112
#define NOTICE
Definition: elog.h:37
bool ii_Unique
Definition: execnodes.h:157
#define Assert(condition)
Definition: c.h:680
bool initdeferred
Definition: parsenodes.h:2725
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:71
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
ObjectAddress index_constraint_create(Relation heapRelation, Oid indexRelationId, IndexInfo *indexInfo, const char *constraintName, char constraintType, bits16 constr_flags, bool allow_system_table_mods, bool is_internal)
Definition: index.c:1149
bool isconstraint
Definition: parsenodes.h:2723
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:69
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition: index.h:68

◆ ATExecAddInherit()

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

Definition at line 11055 of file tablecmds.c.

References AccessShareLock, ATSimplePermissions(), ATT_FOREIGN_TABLE, ATT_TABLE, CreateInheritance(), ereport, errcode(), errdetail(), errmsg(), ERROR, find_all_inheritors(), FindTriggerIncompatibleWithInheritance(), heap_close, heap_openrv(), list_member_oid(), NoLock, ObjectAddressSet, RelationData::rd_islocaltemp, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, RelationRelationId, RELKIND_PARTITIONED_TABLE, RangeVar::relname, RELPERSISTENCE_TEMP, ShareUpdateExclusiveLock, and RelationData::trigdesc.

Referenced by ATExecCmd().

11056 {
11057  Relation parent_rel;
11058  List *children;
11059  ObjectAddress address;
11060  const char *trigger_name;
11061 
11062  /*
11063  * A self-exclusive lock is needed here. See the similar case in
11064  * MergeAttributes() for a full explanation.
11065  */
11066  parent_rel = heap_openrv(parent, ShareUpdateExclusiveLock);
11067 
11068  /*
11069  * Must be owner of both parent and child -- child was checked by
11070  * ATSimplePermissions call in ATPrepCmd
11071  */
11073 
11074  /* Permanent rels cannot inherit from temporary ones */
11075  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
11076  child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
11077  ereport(ERROR,
11078  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11079  errmsg("cannot inherit from temporary relation \"%s\"",
11080  RelationGetRelationName(parent_rel))));
11081 
11082  /* If parent rel is temp, it must belong to this session */
11083  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
11084  !parent_rel->rd_islocaltemp)
11085  ereport(ERROR,
11086  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11087  errmsg("cannot inherit from temporary relation of another session")));
11088 
11089  /* Ditto for the child */
11090  if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
11091  !child_rel->rd_islocaltemp)
11092  ereport(ERROR,
11093  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11094  errmsg("cannot inherit to temporary relation of another session")));
11095 
11096  /* Prevent partitioned tables from becoming inheritance parents */
11097  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
11098  ereport(ERROR,
11099  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11100  errmsg("cannot inherit from partitioned table \"%s\"",
11101  parent->relname)));
11102 
11103  /* Likewise for partitions */
11104  if (parent_rel->rd_rel->relispartition)
11105  ereport(ERROR,
11106  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11107  errmsg("cannot inherit from a partition")));
11108 
11109  /*
11110  * Prevent circularity by seeing if proposed parent inherits from child.
11111  * (In particular, this disallows making a rel inherit from itself.)
11112  *
11113  * This is not completely bulletproof because of race conditions: in
11114  * multi-level inheritance trees, someone else could concurrently be
11115  * making another inheritance link that closes the loop but does not join
11116  * either of the rels we have locked. Preventing that seems to require
11117  * exclusive locks on the entire inheritance tree, which is a cure worse
11118  * than the disease. find_all_inheritors() will cope with circularity
11119  * anyway, so don't sweat it too much.
11120  *
11121  * We use weakest lock we can on child's children, namely AccessShareLock.
11122  */
11123  children = find_all_inheritors(RelationGetRelid(child_rel),
11124  AccessShareLock, NULL);
11125 
11126  if (list_member_oid(children, RelationGetRelid(parent_rel)))
11127  ereport(ERROR,
11128  (errcode(ERRCODE_DUPLICATE_TABLE),
11129  errmsg("circular inheritance not allowed"),
11130  errdetail("\"%s\" is already a child of \"%s\".",
11131  parent->relname,
11132  RelationGetRelationName(child_rel))));
11133 
11134  /* If parent has OIDs then child must have OIDs */
11135  if (parent_rel->rd_rel->relhasoids && !child_rel->rd_rel->relhasoids)
11136  ereport(ERROR,
11137  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11138  errmsg("table \"%s\" without OIDs cannot inherit from table \"%s\" with OIDs",
11139  RelationGetRelationName(child_rel),
11140  RelationGetRelationName(parent_rel))));
11141 
11142  /*
11143  * If child_rel has row-level triggers with transition tables, we
11144  * currently don't allow it to become an inheritance child. See also
11145  * prohibitions in ATExecAttachPartition() and CreateTrigger().
11146  */
11147  trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
11148  if (trigger_name != NULL)
11149  ereport(ERROR,
11150  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11151  errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
11152  trigger_name, RelationGetRelationName(child_rel)),
11153  errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies")));
11154 
11155  /* OK to create inheritance */
11156  CreateInheritance(child_rel, parent_rel);
11157 
11159  RelationGetRelid(parent_rel));
11160 
11161  /* keep our lock on the parent relation until commit */
11162  heap_close(parent_rel, NoLock);
11163 
11164  return address;
11165 }
#define RelationRelationId
Definition: pg_class.h:29
bool rd_islocaltemp
Definition: rel.h:90
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
#define ATT_TABLE
Definition: tablecmds.c:281
static void CreateInheritance(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:11175
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:120
#define NoLock
Definition: lockdefs.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define RelationGetRelationName(relation)
Definition: rel.h:445
#define ereport(elevel, rest)
Definition: elog.h:122
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1318
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:167
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void ATSimplePermissions(Relation rel, int allowed_targets)
Definition: tablecmds.c:4736
#define RELPERSISTENCE_TEMP
Definition: pg_class.h:172
Definition: pg_list.h:45
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:286
#define RelationGetRelid(relation)
Definition: rel.h:425
const char * FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc)
Definition: trigger.c:2096

◆ ATExecAddOf()

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

Definition at line 11879 of file tablecmds.c.

References AccessShareLock, Anum_pg_inherits_inhrelid, BTEqualStrategyNumber, CatalogTupleUpdate(), check_of_type(), ObjectAddress::classId, DecrTupleDescRefCount(), DEPENDENCY_NORMAL, drop_parent_dependency(), elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_close, heap_freetuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InheritsRelationId, InheritsRelidSeqnoIndexId, InvokeObjectPostAlterHook, lookup_rowtype_tupdesc(), NAMEDATALEN, NameStr, tupleDesc::natts, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, RelationData::rd_rel, recordDependencyOn(), RelationGetDescr, RelationGetRelationName, RelationGetRelid, RelationRelationId, ReleaseSysCache(), OnCommitItem::relid, RELOID, RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, TupleDescAttr, typenameType(), and TypeRelationId.

Referenced by ATExecCmd().

11880 {
11881  Oid relid = RelationGetRelid(rel);
11882  Type typetuple;
11883  Oid typeid;
11884  Relation inheritsRelation,
11885  relationRelation;
11886  SysScanDesc scan;
11887  ScanKeyData key;
11888  AttrNumber table_attno,
11889  type_attno;
11890  TupleDesc typeTupleDesc,
11891  tableTupleDesc;
11892  ObjectAddress tableobj,
11893  typeobj;
11894  HeapTuple classtuple;
11895 
11896  /* Validate the type. */
11897  typetuple = typenameType(NULL, ofTypename, NULL);
11898  check_of_type(typetuple);
11899  typeid = HeapTupleGetOid(typetuple);
11900 
11901  /* Fail if the table has any inheritance parents. */
11902  inheritsRelation = heap_open(InheritsRelationId, AccessShareLock);
11903  ScanKeyInit(&key,
11905  BTEqualStrategyNumber, F_OIDEQ,
11906  ObjectIdGetDatum(relid));
11907  scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
11908  true, NULL, 1, &key);
11910  ereport(ERROR,
11911  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11912  errmsg("typed tables cannot inherit")));
11913  systable_endscan(scan);
11914  heap_close(inheritsRelation, AccessShareLock);
11915 
11916  /*
11917  * Check the tuple descriptors for compatibility. Unlike inheritance, we
11918  * require that the order also match. However, attnotnull need not match.
11919  * Also unlike inheritance, we do not require matching relhasoids.
11920  */
11921  typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
11922  tableTupleDesc = RelationGetDescr(rel);
11923  table_attno = 1;
11924  for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
11925  {
11926  Form_pg_attribute type_attr,
11927  table_attr;
11928  const char *type_attname,
11929  *table_attname;
11930 
11931  /* Get the next non-dropped type attribute. */
11932  type_attr = TupleDescAttr(typeTupleDesc, type_attno - 1);
11933  if (type_attr->attisdropped)
11934  continue;
11935  type_attname = NameStr(type_attr->attname);
11936 
11937  /* Get the next non-dropped table attribute. */
11938  do
11939  {
11940  if (table_attno > tableTupleDesc->natts)
11941  ereport(ERROR,
11942  (errcode(ERRCODE_DATATYPE_MISMATCH),
11943  errmsg("table is missing column \"%s\"",
11944  type_attname)));
11945  table_attr = TupleDescAttr(tableTupleDesc, table_attno - 1);
11946  table_attno++;
11947  } while (table_attr->attisdropped);
11948  table_attname = NameStr(table_attr->attname);
11949 
11950  /* Compare name. */
11951  if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
11952  ereport(ERROR,
11953  (errcode(ERRCODE_DATATYPE_MISMATCH),
11954  errmsg("table has column \"%s\" where type requires \"%s\"",
11955  table_attname, type_attname)));
11956 
11957  /* Compare type. */
11958  if (table_attr->atttypid != type_attr->atttypid ||
11959  table_attr->atttypmod != type_attr->atttypmod ||
11960  table_attr->attcollation != type_attr->attcollation)
11961  ereport(ERROR,
11962  (errcode(ERRCODE_DATATYPE_MISMATCH),
11963  errmsg("table \"%s\" has different type for column \"%s\"",
11964  RelationGetRelationName(rel), type_attname)));
11965  }
11966  DecrTupleDescRefCount(typeTupleDesc);
11967 
11968  /* Any remaining columns at the end of the table had better be dropped. */
11969  for (; table_attno <= tableTupleDesc->natts; table_attno++)
11970  {
11971  Form_pg_attribute table_attr = TupleDescAttr(tableTupleDesc,
11972  table_attno - 1);
11973 
11974  if (!table_attr->attisdropped)
11975  ereport(ERROR,
11976  (errcode(ERRCODE_DATATYPE_MISMATCH),
11977  errmsg("table has extra column \"%s\"",
11978  NameStr(table_attr->attname))));
11979  }
11980 
11981  /* If the table was already typed, drop the existing dependency. */
11982  if (rel->rd_rel->reloftype)
11983  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
11985 
11986  /* Record a dependency on the new type. */
11987  tableobj.classId = RelationRelationId;
11988  tableobj.objectId = relid;
11989  tableobj.objectSubId = 0;
11990  typeobj.classId = TypeRelationId;
11991  typeobj.objectId = typeid;
11992  typeobj.objectSubId = 0;
11993  recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
11994 
11995  /* Update pg_class.reloftype */
11996  relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
11997  classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
11998  if (!HeapTupleIsValid(classtuple))
11999  elog(ERROR, "cache lookup failed for relation %u", relid);
12000  ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
12001  CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
12002 
12004 
12005  heap_freetuple(classtuple);
12006  heap_close(relationRelation, RowExclusiveLock);
12007 
12008  ReleaseSysCache(typetuple);
12009 
12010  return typeobj;
12011 }
#define Anum_pg_inherits_inhrelid
Definition: pg_inherits.h:50
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:247
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1618
#define RelationGetDescr(relation)
Definition: rel.h:437
static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
Definition: tablecmds.c:11827
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
#define RelationRelationId
Definition: pg_class.h:29
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
#define TypeRelationId
Definition: pg_type.h:34
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
int natts
Definition: tupdesc.h:79
#define NAMEDATALEN
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
void check_of_type(HeapTuple typetuple)
Definition: tablecmds.c:5108
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:445
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void DecrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:357
#define InheritsRelidSeqnoIndexId
Definition: indexing.h:167
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define InheritsRelationId
Definition: pg_inherits.h:29
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:557
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:700
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:425
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ ATExecAlterColumnGenericOptions()

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

Definition at line 9430 of file tablecmds.c.

References AccessShareLock, Anum_pg_attribute_attfdwoptions, ATTNAME, AttributeRelationId, CatalogTupleUpdate(), DatumGetPointer, ereport, errcode(), errmsg(), ERROR, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, FOREIGNTABLEREL, ForeignTableRelationId, GetForeignDataWrapper(), GetForeignServer(), GETSTRUCT, heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleIsValid, InvalidObjectAddress, InvokeObjectPostAlterHook, Natts_pg_attribute, NIL, ObjectAddressSubSet, PointerGetDatum, PointerIsValid, RelationData::rd_id, RelationGetDescr, RelationGetRelationName, RelationGetRelid, RelationRelationId, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), SearchSysCacheAttName(), SysCacheGetAttr(), HeapTupleData::t_self, and transformGenericOptions().

Referenced by ATExecCmd().

9434 {
9435  Relation ftrel;
9436  Relation attrel;
9437  ForeignServer *server;
9438  ForeignDataWrapper *fdw;
9439  HeapTuple tuple;
9440  HeapTuple newtuple;
9441  bool isnull;
9442  Datum repl_val[Natts_pg_attribute];
9443  bool repl_null[Natts_pg_attribute];
9444  bool repl_repl[Natts_pg_attribute];
9445  Datum datum;
9446  Form_pg_foreign_table fttableform;
9447  Form_pg_attribute atttableform;
9448  AttrNumber attnum;
9449  ObjectAddress address;
9450 
9451  if (options == NIL)
9452  return InvalidObjectAddress;
9453 
9454  /* First, determine FDW validator associated to the foreign table. */
9456  tuple = SearchSysCache1(FOREIGNTABLEREL, rel->rd_id);
9457  if (!HeapTupleIsValid(tuple))
9458  ereport(ERROR,
9459  (errcode(ERRCODE_UNDEFINED_OBJECT),
9460  errmsg("foreign table \"%s\" does not exist",
9461  RelationGetRelationName(rel))));
9462  fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
9463  server = GetForeignServer(fttableform->ftserver);
9464  fdw = GetForeignDataWrapper(server->fdwid);
9465 
9466  heap_close(ftrel, AccessShareLock);
9467  ReleaseSysCache(tuple);
9468 
9470  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
9471  if (!HeapTupleIsValid(tuple))
9472  ereport(ERROR,
9473  (errcode(ERRCODE_UNDEFINED_COLUMN),
9474  errmsg("column \"%s\" of relation \"%s\" does not exist",
9475  colName, RelationGetRelationName(rel))));
9476 
9477  /* Prevent them from altering a system attribute */
9478  atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
9479  attnum = atttableform->attnum;
9480  if (attnum <= 0)
9481  ereport(ERROR,
9482  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9483  errmsg("cannot alter system column \"%s\"", colName)));
9484 
9485 
9486  /* Initialize buffers for new tuple values */
9487  memset(repl_val, 0, sizeof(repl_val));
9488  memset(repl_null, false, sizeof(repl_null));
9489  memset(repl_repl, false, sizeof(repl_repl));
9490 
9491  /* Extract the current options */
9492  datum = SysCacheGetAttr(ATTNAME,
9493  tuple,
9495  &isnull);
9496  if (isnull)
9497  datum = PointerGetDatum(NULL);
9498 
9499  /* Transform the options */
9501  datum,
9502  options,
9503  fdw->fdwvalidator);
9504 
9505  if (PointerIsValid(DatumGetPointer(datum)))
9506  repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
9507  else
9508  repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
9509 
9510  repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
9511 
9512  /* Everything looks good - update the tuple */
9513 
9514  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
9515  repl_val, repl_null, repl_repl);
9516 
9517  CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
9518 
9520  RelationGetRelid(rel),
9521  atttableform->attnum);
9523  RelationGetRelid(rel), attnum);
9524 
9525  ReleaseSysCache(tuple);
9526 
9527  heap_close(attrel, RowExclusiveLock);
9528 
9529  heap_freetuple(newtuple);
9530 
9531  return address;
9532 }
#define NIL
Definition: pg_list.h:69
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define RelationGetDescr(relation)
Definition: rel.h:437
Datum transformGenericOptions(Oid catalogId, Datum oldOptions, List *options, Oid fdwvalidator)
Definition: foreigncmds.c:109
#define PointerGetDatum(X)
Definition: postgres.h:562
#define RelationRelationId
Definition: pg_class.h:29
#define AccessShareLock
Definition: lockdefs.h:36
#define AttributeRelationId
Definition: pg_attribute.h:33
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
Definition: foreign.c:35
FormData_pg_foreign_table * Form_pg_foreign_table
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:445
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
Oid rd_id
Definition: rel.h:116
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
ForeignServer * GetForeignServer(Oid serverid)
Definition: foreign.c:93
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:1248
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
#define Anum_pg_attribute_attfdwoptions
Definition: pg_attribute.h:216
#define DatumGetPointer(X)
Definition: postgres.h:555
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ForeignTableRelationId
#define Natts_pg_attribute
Definition: pg_attribute.h:194
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:794
#define PointerIsValid(pointer)
Definition: c.h:574
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:425

◆ ATExecAlterColumnType()

static ObjectAddress ATExecAlterColumnType ( AlteredTableInfo tab,
Relation  rel,
AlterTableCmd cmd,
LOCKMODE  lockmode 
)
static

Definition at line 9008 of file tablecmds.c.

References add_column_collation_dependency(), add_column_datatype_dependency(), Anum_pg_depend_classid, Anum_pg_depend_objid, Anum_pg_depend_objsubid, Anum_pg_depend_refclassid, Anum_pg_depend_refobjid, Anum_pg_depend_refobjsubid, Assert, AttributeRelationId, BTEqualStrategyNumber, build_column_default(), CatalogTupleDelete(), CatalogTupleUpdate(), AlteredTableInfo::changedConstraintDefs, AlteredTableInfo::changedConstraintOids, AlteredTableInfo::changedIndexDefs, AlteredTableInfo::changedIndexOids, ObjectAddress::classId, COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, CollationRelationId, CommandCounterIncrement(), AlterTableCmd::def, DependDependerIndexId, DEPENDENCY_NORMAL, DEPENDENCY_PIN, DependReferenceIndexId, DependRelationId, DROP_RESTRICT, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, exprType(), format_type_be(), get_rel_relkind(), GetColumnDefCollation(), getObjectClass(), getObjectDescription(), GETSTRUCT, heap_close, heap_freetuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, Int32GetDatum, InvokeObjectPostAlterHook, lappend(), lappend_oid(), lcons(), lcons_oid(), list_length(), list_member_oid(), AlterTableCmd::name, ObjectAddressSubSet, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OCLASS_AM, OCLASS_AMOP, OCLASS_AMPROC, OCLASS_CAST, OCLASS_CLASS, OCLASS_COLLATION, OCLASS_CONSTRAINT, OCLASS_CONVERSION, OCLASS_DATABASE, OCLASS_DEFACL, OCLASS_DEFAULT, OCLASS_EVENT_TRIGGER, OCLASS_EXTENSION, OCLASS_FDW, OCLASS_FOREIGN_SERVER, OCLASS_LANGUAGE, OCLASS_LARGEOBJECT, OCLASS_OPCLASS, OCLASS_OPERATOR, OCLASS_OPFAMILY, OCLASS_POLICY, OCLASS_PROC, OCLASS_PUBLICATION, OCLASS_PUBLICATION_REL, OCLASS_REWRITE, OCLASS_ROLE, OCLASS_SCHEMA, OCLASS_STATISTIC_EXT, OCLASS_SUBSCRIPTION, OCLASS_TBLSPACE, OCLASS_TRANSFORM, OCLASS_TRIGGER, OCLASS_TSCONFIG, OCLASS_TSDICT, OCLASS_TSPARSER, OCLASS_TSTEMPLATE, OCLASS_TYPE, OCLASS_USER_MAPPING, AlteredTableInfo::oldDesc, pg_get_constraintdef_command(), pg_get_indexdef_string(), RelationGetRelationName, RelationGetRelid, RelationRelationId, ReleaseSysCache(), RELKIND_INDEX, RELKIND_SEQUENCE, RemoveAttrDefault(), RemoveStatistics(), RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopyAttName(), StoreAttrDefault(), strip_implicit_coercions(), systable_beginscan(), systable_endscan(), systable_getnext(), TupleDescAttr, ColumnDef::typeName, typenameType(), TypeRelationId, and UpdateStatisticsForTypeChange().

Referenced by ATExecCmd().

9010 {
9011  char *colName = cmd->name;
9012  ColumnDef *def = (ColumnDef *) cmd->def;
9013  TypeName *typeName = def->typeName;
9014  HeapTuple heapTup;
9015  Form_pg_attribute attTup,
9016  attOldTup;
9017  AttrNumber attnum;
9018  HeapTuple typeTuple;
9019  Form_pg_type tform;
9020  Oid targettype;
9021  int32 targettypmod;
9022  Oid targetcollid;
9023  Node *defaultexpr;
9024  Relation attrelation;
9025  Relation depRel;
9026  ScanKeyData key[3];
9027  SysScanDesc scan;
9028  HeapTuple depTup;
9029  ObjectAddress address;
9030 
9032 
9033  /* Look up the target column */
9034  heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
9035  if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */
9036  ereport(ERROR,
9037  (errcode(ERRCODE_UNDEFINED_COLUMN),
9038  errmsg("column \"%s\" of relation \"%s\" does not exist",
9039  colName, RelationGetRelationName(rel))));
9040  attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
9041  attnum = attTup->attnum;
9042  attOldTup = TupleDescAttr(tab->oldDesc, attnum - 1);
9043 
9044  /* Check for multiple ALTER TYPE on same column --- can't cope */
9045  if (attTup->atttypid != attOldTup->atttypid ||
9046  attTup->atttypmod != attOldTup->atttypmod)
9047  ereport(ERROR,
9048  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9049  errmsg("cannot alter type of column \"%s\" twice",
9050  colName)));
9051 
9052  /* Look up the target type (should not fail, since prep found it) */
9053  typeTuple = typenameType(NULL, typeName, &targettypmod);
9054  tform = (Form_pg_type) GETSTRUCT(typeTuple);
9055  targettype = HeapTupleGetOid(typeTuple);
9056  /* And the collation */
9057  targetcollid = GetColumnDefCollation(NULL, def, targettype);
9058 
9059  /*
9060  * If there is a default expression for the column, get it and ensure we
9061  * can coerce it to the new datatype. (We must do this before changing
9062  * the column type, because build_column_default itself will try to
9063  * coerce, and will not issue the error message we want if it fails.)
9064  *
9065  * We remove any implicit coercion steps at the top level of the old
9066  * default expression; this has been agreed to satisfy the principle of
9067  * least surprise. (The conversion to the new column type should act like
9068  * it started from what the user sees as the stored expression, and the
9069  * implicit coercions aren't going to be shown.)
9070  */
9071  if (attTup->atthasdef)
9072  {
9073  defaultexpr = build_column_default(rel, attnum);
9074  Assert(defaultexpr);
9075  defaultexpr = strip_implicit_coercions(defaultexpr);
9076  defaultexpr = coerce_to_target_type(NULL, /* no UNKNOWN params */
9077  defaultexpr, exprType(defaultexpr),
9078  targettype, targettypmod,
9081  -1);
9082  if (defaultexpr == NULL)
9083  ereport(ERROR,
9084  (errcode(ERRCODE_DATATYPE_MISMATCH),
9085  errmsg("default for column \"%s\" cannot be cast automatically to type %s",
9086  colName, format_type_be(targettype))));
9087  }
9088  else
9089  defaultexpr = NULL;
9090 
9091  /*
9092  * Find everything that depends on the column (constraints, indexes, etc),
9093  * and record enough information to let us recreate the objects.
9094  *
9095  * The actual recreation does not happen here, but only after we have
9096  * performed all the individual ALTER TYPE operations. We have to save
9097  * the info before executing ALTER TYPE, though, else the deparser will
9098  * get confused.
9099  *
9100  * There could be multiple entries for the same object, so we must check
9101  * to ensure we process each one only once. Note: we assume that an index
9102  * that implements a constraint will not show a direct dependency on the
9103  * column.
9104  */
9106 
9107  ScanKeyInit(&key[0],
9109  BTEqualStrategyNumber, F_OIDEQ,
9111  ScanKeyInit(&key[1],
9113  BTEqualStrategyNumber, F_OIDEQ,
9115  ScanKeyInit(&key[2],
9117  BTEqualStrategyNumber, F_INT4EQ,
9118  Int32GetDatum((int32) attnum));
9119 
9120  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
9121  NULL, 3, key);
9122 
9123  while (HeapTupleIsValid(depTup = systable_getnext(scan)))
9124  {
9125  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
9126  ObjectAddress foundObject;
9127 
9128  /* We don't expect any PIN dependencies on columns */
9129  if (foundDep->deptype == DEPENDENCY_PIN)
9130  elog(ERROR, "cannot alter type of a pinned column");
9131 
9132  foundObject.classId = foundDep->classid;
9133  foundObject.objectId = foundDep->objid;
9134  foundObject.objectSubId = foundDep->objsubid;
9135 
9136  switch (getObjectClass(&foundObject))
9137  {
9138  case OCLASS_CLASS:
9139  {
9140  char relKind = get_rel_relkind(foundObject.objectId);
9141 
9142  if (relKind == RELKIND_INDEX)
9143  {
9144  Assert(foundObject.objectSubId == 0);
9145  if (!list_member_oid(tab->changedIndexOids, foundObject.objectId))
9146  {
9148  foundObject.objectId);
9150  pg_get_indexdef_string(foundObject.objectId));
9151  }
9152  }
9153  else if (relKind == RELKIND_SEQUENCE)
9154  {
9155  /*
9156  * This must be a SERIAL column's sequence. We need
9157  * not do anything to it.
9158  */
9159  Assert(foundObject.objectSubId == 0);
9160  }
9161  else
9162  {
9163  /* Not expecting any other direct dependencies... */
9164  elog(ERROR, "unexpected object depending on column: %s",
9165  getObjectDescription(&foundObject));
9166  }
9167  break;
9168  }
9169 
9170  case OCLASS_CONSTRAINT:
9171  Assert(foundObject.objectSubId == 0);
9173  foundObject.objectId))
9174  {
9175  char *defstring = pg_get_constraintdef_command(foundObject.objectId);
9176 
9177  /*
9178  * Put NORMAL dependencies at the front of the list and
9179  * AUTO dependencies at the back. This makes sure that
9180  * foreign-key constraints depending on this column will
9181  * be dropped before unique or primary-key constraints of
9182  * the column; which we must have because the FK
9183  * constraints depend on the indexes belonging to the
9184  * unique constraints.
9185  */
9186  if (foundDep->deptype == DEPENDENCY_NORMAL)
9187  {
9188  tab->changedConstraintOids =
9189  lcons_oid(foundObject.objectId,
9190  tab->changedConstraintOids);
9191  tab->changedConstraintDefs =
9192  lcons(defstring,
9193  tab->changedConstraintDefs);
9194  }
9195  else
9196  {
9197  tab->changedConstraintOids =
9199  foundObject.objectId);
9200  tab->changedConstraintDefs =
9202  defstring);
9203  }
9204  }
9205  break;
9206 
9207  case OCLASS_REWRITE:
9208  /* XXX someday see if we can cope with revising views */
9209  ereport(ERROR,
9210  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9211  errmsg("cannot alter type of a column used by a view or rule"),
9212  errdetail("%s depends on column \"%s\"",
9213  getObjectDescription(&foundObject),
9214  colName)));
9215  break;
9216 
9217  case OCLASS_TRIGGER:
9218 
9219  /*
9220  * A trigger can depend on a column because the column is
9221  * specified as an update target, or because the column is
9222  * used in the trigger's WHEN condition. The first case would
9223  * not require any extra work, but the second case would
9224  * require updating the WHEN expression, which will take a
9225  * significant amount of new code. Since we can't easily tell
9226  * which case applies, we punt for both. FIXME someday.
9227  */
9228  ereport(ERROR,
9229  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9230  errmsg("cannot alter type of a column used in a trigger definition"),
9231  errdetail("%s depends on column \"%s\"",
9232  getObjectDescription(&foundObject),
9233  colName)));
9234  break;
9235 
9236  case OCLASS_POLICY:
9237 
9238  /*
9239  * A policy can depend on a column because the column is
9240  * specified in the policy's USING or WITH CHECK qual
9241  * expressions. It might be possible to rewrite and recheck
9242  * the policy expression, but punt for now. It's certainly
9243  * easy enough to remove and recreate the policy; still, FIXME
9244  * someday.
9245  */
9246  ereport(ERROR,
9247  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9248  errmsg("cannot alter type of a column used in a policy definition"),
9249  errdetail("%s depends on column \"%s\"",
9250  getObjectDescription(&foundObject),
9251  colName)));
9252  break;
9253 
9254  case OCLASS_DEFAULT:
9255 
9256  /*
9257  * Ignore the column's default expression, since we will fix
9258  * it below.
9259  */
9260  Assert(defaultexpr);
926