PostgreSQL Source Code  git master
tablecmds.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/heapam_xlog.h"
#include "access/multixact.h"
#include "access/reloptions.h"
#include "access/relscan.h"
#include "access/tableam.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_depend.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "catalog/toasting.h"
#include "commands/cluster.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/policy.h"
#include "commands/sequence.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
#include "commands/user.h"
#include "executor/executor.h"
#include "foreign/foreign.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/parsenodes.h"
#include "optimizer/optimizer.h"
#include "parser/parse_clause.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "parser/parse_utilcmd.h"
#include "parser/parser.h"
#include "partitioning/partbounds.h"
#include "partitioning/partdesc.h"
#include "pgstat.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteHandler.h"
#include "rewrite/rewriteManip.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "storage/lock.h"
#include "storage/predicate.h"
#include "storage/smgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/partcache.h"
#include "utils/relcache.h"
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/timestamp.h"
#include "utils/typcache.h"
Include dependency graph for tablecmds.c:

Go to the source code of this file.

Data Structures

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

Macros

#define AT_PASS_UNSET   -1 /* UNSET will cause ERROR */
 
#define AT_PASS_DROP   0 /* DROP (all flavors) */
 
#define AT_PASS_ALTER_TYPE   1 /* ALTER COLUMN TYPE */
 
#define AT_PASS_OLD_INDEX   2 /* re-add existing indexes */
 
#define AT_PASS_OLD_CONSTR   3 /* re-add existing constraints */
 
#define AT_PASS_ADD_COL   4 /* ADD COLUMN */
 
#define AT_PASS_COL_ATTRS   5 /* set other column attributes */
 
#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 ATT_PARTITIONED_INDEX   0x0040
 
#define child_dependency_type(child_is_partition)   ((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
 

Typedefs

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

Functions

static void truncate_check_rel (Oid relid, Form_pg_class reltuple)
 
static void truncate_check_activity (Relation rel)
 
static void RangeVarCallbackForTruncate (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
static ListMergeAttributes (List *schema, List *supers, char relpersistence, bool is_partition, List **supconstr)
 
static bool MergeCheckConstraint (List *constraints, char *name, Node *expr)
 
static void MergeAttributesIntoExisting (Relation child_rel, Relation parent_rel)
 
static void MergeConstraintsIntoExisting (Relation child_rel, Relation parent_rel)
 
static void StoreCatalogInheritance (Oid relationId, List *supers, bool child_is_partition)
 
static void StoreCatalogInheritance1 (Oid relationId, Oid parentOid, int32 seqNumber, Relation inhRelation, bool child_is_partition)
 
static int findAttrByName (const char *attributeName, List *schema)
 
static void AlterIndexNamespaces (Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
 
static void AlterSeqNamespaces (Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
 
static ObjectAddress ATExecAlterConstraint (Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
 
static ObjectAddress ATExecValidateConstraint (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 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 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 ATPrepDropNotNull (Relation rel, bool recurse, bool recursing)
 
static ObjectAddress ATExecDropNotNull (Relation rel, const char *colName, LOCKMODE lockmode)
 
static void ATPrepSetNotNull (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetNotNull (AlteredTableInfo *tab, Relation rel, const char *colName, LOCKMODE lockmode)
 
static void ATExecCheckNotNull (AlteredTableInfo *tab, Relation rel, const char *colName, LOCKMODE lockmode)
 
static bool NotNullImpliedByRelConstraints (Relation rel, Form_pg_attribute attr)
 
static bool ConstraintImpliedByRelConstraint (Relation scanrel, List *testConstraint, List *provenConstraint)
 
static ObjectAddress ATExecColumnDefault (Relation rel, const char *colName, Node *newDefault, LOCKMODE lockmode)
 
static ObjectAddress 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 char * ChooseForeignKeyConstraintNameAddition (List *colnames)
 
static ObjectAddress ATExecAddIndexConstraint (AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, LOCKMODE lockmode)
 
static ObjectAddress ATAddCheckConstraint (List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
 
static ObjectAddress ATAddForeignKeyConstraint (List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, Oid parentConstr, bool recurse, bool recursing, LOCKMODE lockmode)
 
static ObjectAddress addFkRecurseReferenced (List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok)
 
static void addFkRecurseReferencing (List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok, LOCKMODE lockmode)
 
static void CloneForeignKeyConstraints (List **wqueue, Relation parentRel, Relation partitionRel)
 
static void CloneFkReferenced (Relation parentRel, Relation partitionRel)
 
static void CloneFkReferencing (List **wqueue, Relation parentRel, Relation partRel)
 
static void createForeignKeyCheckTriggers (Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
 
static void createForeignKeyActionTriggers (Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
 
static bool tryAttachPartitionForeignKey (ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop)
 
static void ATExecDropConstraint (Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode)
 
static void ATPrepAlterColumnType (List **wqueue, AlteredTableInfo *tab, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode)
 
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 ATExecSetTableSpaceNoStorage (Relation rel, Oid newTableSpace)
 
static void ATExecSetRelOptions (Relation rel, List *defList, AlterTableType operation, LOCKMODE lockmode)
 
static void ATExecEnableDisableTrigger (Relation rel, const char *trigname, char fires_when, bool skip_system, LOCKMODE lockmode)
 
static void ATExecEnableDisableRule (Relation rel, const char *rulename, char fires_when, LOCKMODE lockmode)
 
static void ATPrepAddInherit (Relation child_rel)
 
static ObjectAddress ATExecAddInherit (Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
 
static ObjectAddress ATExecDropInherit (Relation rel, RangeVar *parent, LOCKMODE lockmode)
 
static void drop_parent_dependency (Oid relid, Oid refclassid, Oid refobjid, DependencyType deptype)
 
static ObjectAddress ATExecAddOf (Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
 
static void ATExecDropOf (Relation rel, LOCKMODE lockmode)
 
static void ATExecReplicaIdentity (Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
 
static void ATExecGenericOptions (Relation rel, List *options)
 
static void ATExecEnableRowSecurity (Relation rel)
 
static void ATExecDisableRowSecurity (Relation rel)
 
static void ATExecForceNoForceRowSecurity (Relation rel, bool force_rls)
 
static void index_copy_data (Relation rel, RelFileNode newrnode)
 
static const char * storage_name (char c)
 
static void RangeVarCallbackForDropRelation (const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
 
static void RangeVarCallbackForAlterRelation (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
static PartitionSpectransformPartitionSpec (Relation rel, PartitionSpec *partspec, char *strategy)
 
static void ComputePartitionAttrs (ParseState *pstate, Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation, char strategy)
 
static void CreateInheritance (Relation child_rel, Relation parent_rel)
 
static void RemoveInheritance (Relation child_rel, Relation parent_rel)
 
static ObjectAddress ATExecAttachPartition (List **wqueue, Relation rel, PartitionCmd *cmd)
 
static void AttachPartitionEnsureIndexes (Relation rel, Relation attachrel)
 
static void QueuePartitionConstraintValidation (List **wqueue, Relation scanrel, List *partConstraint, bool validate_default)
 
static void CloneRowTriggersToPartition (Relation parent, Relation partition)
 
static ObjectAddress ATExecDetachPartition (Relation rel, RangeVar *name)
 
static ObjectAddress ATExecAttachPartitionIdx (List **wqueue, Relation rel, RangeVar *name)
 
static void validatePartitionedIndex (Relation partedIdx, Relation partedTbl)
 
static void refuseDupeIndexAttach (Relation parentIdx, Relation partIdx, Relation partitionTbl)
 
static ListGetParentedForeignKeyRefs (Relation partition)
 
static void ATDetachCheckNoForeignKeyRefs (Relation partition)
 
ObjectAddress DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
 
static void DropErrorMsgNonExistent (RangeVar *rel, char rightkind, bool missing_ok)
 
static void DropErrorMsgWrongType (const char *relname, char wrongkind, char rightkind)
 
void RemoveRelations (DropStmt *drop)
 
void ExecuteTruncate (TruncateStmt *stmt)
 
void ExecuteTruncateGuts (List *explicit_rels, List *relids, List *relids_logged, DropBehavior behavior, bool restart_seqs)
 
void SetRelationHasSubclass (Oid relationId, bool relhassubclass)
 
static void renameatt_check (Oid myrelid, Form_pg_class classform, bool recursing)
 
static AttrNumber renameatt_internal (Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
 
static void RangeVarCallbackForRenameAttribute (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
ObjectAddress renameatt (RenameStmt *stmt)
 
static ObjectAddress rename_constraint_internal (Oid myrelid, Oid mytypid, const char *oldconname, const char *newconname, bool recurse, bool recursing, int expected_parents)
 
ObjectAddress RenameConstraint (RenameStmt *stmt)
 
ObjectAddress RenameRelation (RenameStmt *stmt)
 
void RenameRelationInternal (Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
 
void CheckTableNotInUse (Relation rel, const char *stmt)
 
Oid AlterTableLookupRelation (AlterTableStmt *stmt, LOCKMODE lockmode)
 
void AlterTable (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)
 
static void RangeVarCallbackForAttachIndex (const RangeVar *rv, Oid relOid, Oid oldRelOid, void *arg)
 

Variables

static Liston_commits = NIL
 
static const struct dropmsgstrings dropmsgstringarray []
 

Macro Definition Documentation

◆ AT_NUM_PASSES

#define AT_NUM_PASSES   9

Definition at line 151 of file tablecmds.c.

Referenced by ATRewriteCatalogs().

◆ AT_PASS_ADD_COL

#define AT_PASS_ADD_COL   4 /* ADD COLUMN */

Definition at line 146 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_ADD_CONSTR

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

Definition at line 149 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_ADD_INDEX

#define AT_PASS_ADD_INDEX   6 /* ADD indexes */

Definition at line 148 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_ALTER_TYPE

#define AT_PASS_ALTER_TYPE   1 /* ALTER COLUMN TYPE */

Definition at line 142 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATRewriteCatalogs().

◆ AT_PASS_COL_ATTRS

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

Definition at line 147 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_DROP

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

Definition at line 141 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_MISC

#define AT_PASS_MISC   8 /* other stuff */

Definition at line 150 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ AT_PASS_OLD_CONSTR

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

Definition at line 144 of file tablecmds.c.

Referenced by ATPostAlterTypeParse().

◆ AT_PASS_OLD_INDEX

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

Definition at line 143 of file tablecmds.c.

Referenced by ATPostAlterTypeParse().

◆ AT_PASS_UNSET

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

Definition at line 140 of file tablecmds.c.

Referenced by ATPrepCmd().

◆ ATT_COMPOSITE_TYPE

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 290 of file tablecmds.c.

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

◆ ATT_FOREIGN_TABLE

◆ ATT_INDEX

#define ATT_INDEX   0x0008

Definition at line 289 of file tablecmds.c.

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

◆ ATT_MATVIEW

#define ATT_MATVIEW   0x0004

Definition at line 288 of file tablecmds.c.

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

◆ ATT_PARTITIONED_INDEX

#define ATT_PARTITIONED_INDEX   0x0040

Definition at line 292 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATSimplePermissions().

◆ ATT_TABLE

◆ ATT_VIEW

#define ATT_VIEW   0x0002

Definition at line 287 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 299 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 5977 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

5978 {
5979  ObjectAddress myself,
5980  referenced;
5981 
5982  /* We know the default collation is pinned, so don't bother recording it */
5983  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
5984  {
5985  myself.classId = RelationRelationId;
5986  myself.objectId = relid;
5987  myself.objectSubId = attnum;
5988  referenced.classId = CollationRelationId;
5989  referenced.objectId = collid;
5990  referenced.objectSubId = 0;
5991  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
5992  }
5993 }
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
#define OidIsValid(objectId)
Definition: c.h:638
int16 attnum
Definition: pg_attribute.h:79

◆ add_column_datatype_dependency()

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

Definition at line 5959 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

5960 {
5961  ObjectAddress myself,
5962  referenced;
5963 
5964  myself.classId = RelationRelationId;
5965  myself.objectId = relid;
5966  myself.objectSubId = attnum;
5967  referenced.classId = TypeRelationId;
5968  referenced.objectId = typid;
5969  referenced.objectSubId = 0;
5970  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
5971 }
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
int16 attnum
Definition: pg_attribute.h:79

◆ addFkRecurseReferenced()

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

Definition at line 7982 of file tablecmds.c.

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

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferenced().

7987 {
7988  ObjectAddress address;
7989  Oid constrOid;
7990  char *conname;
7991  bool conislocal;
7992  int coninhcount;
7993  bool connoinherit;
7994 
7995  /*
7996  * Verify relkind for each referenced partition. At the top level, this
7997  * is redundant with a previous check, but we need it when recursing.
7998  */
7999  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
8000  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
8001  ereport(ERROR,
8002  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8003  errmsg("referenced relation \"%s\" is not a table",
8004  RelationGetRelationName(pkrel))));
8005 
8006  /*
8007  * Caller supplies us with a constraint name; however, it may be used in
8008  * this partition, so come up with a different one in that case.
8009  */
8011  RelationGetRelid(rel),
8012  fkconstraint->conname))
8015  "fkey",
8016  RelationGetNamespace(rel), NIL);
8017  else
8018  conname = fkconstraint->conname;
8019 
8020  if (OidIsValid(parentConstr))
8021  {
8022  conislocal = false;
8023  coninhcount = 1;
8024  connoinherit = false;
8025  }
8026  else
8027  {
8028  conislocal = true;
8029  coninhcount = 0;
8030 
8031  /*
8032  * always inherit for partitioned tables, never for legacy inheritance
8033  */
8034  connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
8035  }
8036 
8037  /*
8038  * Record the FK constraint in pg_constraint.
8039  */
8040  constrOid = CreateConstraintEntry(conname,
8041  RelationGetNamespace(rel),
8042  CONSTRAINT_FOREIGN,
8043  fkconstraint->deferrable,
8044  fkconstraint->initdeferred,
8045  fkconstraint->initially_valid,
8046  parentConstr,
8047  RelationGetRelid(rel),
8048  fkattnum,
8049  numfks,
8050  numfks,
8051  InvalidOid, /* not a domain constraint */
8052  indexOid,
8053  RelationGetRelid(pkrel),
8054  pkattnum,
8055  pfeqoperators,
8056  ppeqoperators,
8057  ffeqoperators,
8058  numfks,
8059  fkconstraint->fk_upd_action,
8060  fkconstraint->fk_del_action,
8061  fkconstraint->fk_matchtype,
8062  NULL, /* no exclusion constraint */
8063  NULL, /* no check constraint */
8064  NULL,
8065  conislocal, /* islocal */
8066  coninhcount, /* inhcount */
8067  connoinherit, /* conNoInherit */
8068  false); /* is_internal */
8069 
8070  ObjectAddressSet(address, ConstraintRelationId, constrOid);
8071 
8072  /*
8073  * Mark the child constraint as part of the parent constraint; it must not
8074  * be dropped on its own. (This constraint is deleted when the partition
8075  * is detached, but a special check needs to occur that the partition
8076  * contains no referenced values.)
8077  */
8078  if (OidIsValid(parentConstr))
8079  {
8080  ObjectAddress referenced;
8081 
8082  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
8083  recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
8084  }
8085 
8086  /* make new constraint visible, in case we add more */
8088 
8089  /*
8090  * If the referenced table is a plain relation, create the action triggers
8091  * that enforce the constraint.
8092  */
8093  if (pkrel->rd_rel->relkind == RELKIND_RELATION)
8094  {
8096  fkconstraint,
8097  constrOid, indexOid);
8098  }
8099 
8100  /*
8101  * If the referenced table is partitioned, recurse on ourselves to handle
8102  * each partition. We need one pg_constraint row created for each
8103  * partition in addition to the pg_constraint row for the parent table.
8104  */
8105  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8106  {
8108 
8109  for (int i = 0; i < pd->nparts; i++)
8110  {
8111  Relation partRel;
8112  AttrNumber *map;
8113  AttrNumber *mapped_pkattnum;
8114  Oid partIndexId;
8115 
8116  partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
8117 
8118  /*
8119  * Map the attribute numbers in the referenced side of the FK
8120  * definition to match the partition's column layout.
8121  */
8123  RelationGetDescr(pkrel),
8124  gettext_noop("could not convert row type"));
8125  if (map)
8126  {
8127  mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
8128  for (int j = 0; j < numfks; j++)
8129  mapped_pkattnum[j] = map[pkattnum[j] - 1];
8130  }
8131  else
8132  mapped_pkattnum = pkattnum;
8133 
8134  /* do the deed */
8135  partIndexId = index_get_partition(partRel, indexOid);
8136  if (!OidIsValid(partIndexId))
8137  elog(ERROR, "index for %u not found in partition %s",
8138  indexOid, RelationGetRelationName(partRel));
8139  addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
8140  partIndexId, constrOid, numfks,
8141  mapped_pkattnum, fkattnum,
8142  pfeqoperators, ppeqoperators, ffeqoperators,
8143  old_check_ok);
8144 
8145  /* Done -- clean up (but keep the lock) */
8146  table_close(partRel, NoLock);
8147  if (map)
8148  {
8149  pfree(mapped_pkattnum);
8150  pfree(map);
8151  }
8152  }
8153  }
8154 
8155  return address;
8156 }
#define NIL
Definition: pg_list.h:69
Oid index_get_partition(Relation partition, Oid indexId)
Definition: partition.c:154
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:7365
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define RelationGetDescr(relation)
Definition: rel.h:440
char fk_matchtype
Definition: parsenodes.h:2166
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:51
#define gettext_noop(x)
Definition: c.h:1103
int errcode(int sqlerrcode)
Definition: elog.c:570
bool initdeferred
Definition: parsenodes.h:2134
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
char * conname
Definition: parsenodes.h:2132
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:638
AttrNumber * convert_tuples_by_name_map_if_req(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:329
void pfree(void *pointer)
Definition: mcxt.c:1031
static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok)
Definition: tablecmds.c:7982
#define ERROR
Definition: elog.h:43
bool deferrable
Definition: parsenodes.h:2133
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:448
#define ereport(elevel, rest)
Definition: elog.h:141
static void createForeignKeyActionTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:9813
void CommandCounterIncrement(void)
Definition: xact.c:1003
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2175
char fk_del_action
Definition: parsenodes.h:2168
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
int i
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:414
List * fk_attrs
Definition: parsenodes.h:2164
char fk_upd_action
Definition: parsenodes.h:2167
#define RelationGetPartitionDesc(relation)
Definition: rel.h:601
#define RelationGetNamespace(relation)
Definition: rel.h:455

◆ addFkRecurseReferencing()

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

Definition at line 8188 of file tablecmds.c.

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

Referenced by ATAddForeignKeyConstraint(), and CloneFkReferencing().

8193 {
8194  AssertArg(OidIsValid(parentConstr));
8195 
8196  if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
8197  ereport(ERROR,
8198  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
8199  errmsg("foreign key constraints are not supported on foreign tables")));
8200 
8201  /*
8202  * If the referencing relation is a plain table, add the check triggers to
8203  * it and, if necessary, schedule it to be checked in Phase 3.
8204  *
8205  * If the relation is partitioned, drill down to do it to its partitions.
8206  */
8207  if (rel->rd_rel->relkind == RELKIND_RELATION)
8208  {
8210  RelationGetRelid(pkrel),
8211  fkconstraint,
8212  parentConstr,
8213  indexOid);
8214 
8215  /*
8216  * Tell Phase 3 to check that the constraint is satisfied by existing
8217  * rows. We can skip this during table creation, when requested
8218  * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
8219  * and when we're recreating a constraint following a SET DATA TYPE
8220  * operation that did not impugn its validity.
8221  */
8222  if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
8223  {
8224  NewConstraint *newcon;
8225  AlteredTableInfo *tab;
8226 
8227  tab = ATGetQueueEntry(wqueue, rel);
8228 
8229  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
8230  newcon->name = get_constraint_name(parentConstr);
8231  newcon->contype = CONSTR_FOREIGN;
8232  newcon->refrelid = RelationGetRelid(pkrel);
8233  newcon->refindid = indexOid;
8234  newcon->conid = parentConstr;
8235  newcon->qual = (Node *) fkconstraint;
8236 
8237  tab->constraints = lappend(tab->constraints, newcon);
8238  }
8239  }
8240  else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
8241  {
8243 
8244  /*
8245  * Recurse to take appropriate action on each partition; either we
8246  * find an existing constraint to reparent to ours, or we create a new
8247  * one.
8248  */
8249  for (int i = 0; i < pd->nparts; i++)
8250  {
8251  Oid partitionId = pd->oids[i];
8252  Relation partition = table_open(partitionId, lockmode);
8253  List *partFKs;
8254  AttrNumber *attmap;
8255  AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
8256  bool attached;
8257  char *conname;
8258  Oid constrOid;
8259  ObjectAddress address,
8260  referenced;
8261  ListCell *cell;
8262 
8263  CheckTableNotInUse(partition, "ALTER TABLE");
8264 
8265  attmap = convert_tuples_by_name_map(RelationGetDescr(partition),
8266  RelationGetDescr(rel),
8267  gettext_noop("could not convert row type"));
8268  for (int j = 0; j < numfks; j++)
8269  mapped_fkattnum[j] = attmap[fkattnum[j] - 1];
8270 
8271  /* Check whether an existing constraint can be repurposed */
8272  partFKs = copyObject(RelationGetFKeyList(partition));
8273  attached = false;
8274  foreach(cell, partFKs)
8275  {
8276  ForeignKeyCacheInfo *fk;
8277 
8278  fk = lfirst_node(ForeignKeyCacheInfo, cell);
8280  partitionId,
8281  parentConstr,
8282  numfks,
8283  mapped_fkattnum,
8284  pkattnum,
8285  pfeqoperators))
8286  {
8287  attached = true;
8288  break;
8289  }
8290  }
8291  if (attached)
8292  {
8293  table_close(partition, NoLock);
8294  continue;
8295  }
8296 
8297  /*
8298  * No luck finding a good constraint to reuse; create our own.
8299  */
8301  RelationGetRelid(partition),
8302  fkconstraint->conname))
8303  conname = ChooseConstraintName(RelationGetRelationName(partition),
8305  "fkey",
8306  RelationGetNamespace(partition), NIL);
8307  else
8308  conname = fkconstraint->conname;
8309  constrOid =
8310  CreateConstraintEntry(conname,
8311  RelationGetNamespace(partition),
8312  CONSTRAINT_FOREIGN,
8313  fkconstraint->deferrable,
8314  fkconstraint->initdeferred,
8315  fkconstraint->initially_valid,
8316  parentConstr,
8317  partitionId,
8318  mapped_fkattnum,
8319  numfks,
8320  numfks,
8321  InvalidOid,
8322  indexOid,
8323  RelationGetRelid(pkrel),
8324  pkattnum,
8325  pfeqoperators,
8326  ppeqoperators,
8327  ffeqoperators,
8328  numfks,
8329  fkconstraint->fk_upd_action,
8330  fkconstraint->fk_del_action,
8331  fkconstraint->fk_matchtype,
8332  NULL,
8333  NULL,
8334  NULL,
8335  false,
8336  1,
8337  false,
8338  false);
8339 
8340  /*
8341  * Give this constraint partition-type dependencies on the parent
8342  * constraint as well as the table.
8343  */
8344  ObjectAddressSet(address, ConstraintRelationId, constrOid);
8345  ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
8346  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
8347  ObjectAddressSet(referenced, RelationRelationId, partitionId);
8348  recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
8349 
8350  /* Make all this visible before recursing */
8352 
8353  /* call ourselves to finalize the creation and we're done */
8354  addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
8355  indexOid,
8356  constrOid,
8357  numfks,
8358  pkattnum,
8359  mapped_fkattnum,
8360  pfeqoperators,
8361  ppeqoperators,
8362  ffeqoperators,
8363  old_check_ok,
8364  lockmode);
8365 
8366  table_close(partition, NoLock);
8367  }
8368  }
8369 }
#define NIL
Definition: pg_list.h:69
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
static void createForeignKeyCheckTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:9934
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
char * name
Definition: tablecmds.c:183
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:7365
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define RelationGetDescr(relation)
Definition: rel.h:440
char * get_constraint_name(Oid conoid)
Definition: lsyscache.c:969
static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok, LOCKMODE lockmode)
Definition: tablecmds.c:8188
char fk_matchtype
Definition: parsenodes.h:2166
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:51
Node * qual
Definition: tablecmds.c:188
#define gettext_noop(x)
Definition: c.h:1103
Definition: nodes.h:524
int errcode(int sqlerrcode)
Definition: elog.c:570
bool initdeferred
Definition: parsenodes.h:2134
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
char * conname
Definition: parsenodes.h:2132
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:638
List * constraints
Definition: tablecmds.c:162
static bool tryAttachPartitionForeignKey(ForeignKeyCacheInfo *fk, Oid partRelid, Oid parentConstrOid, int numfks, AttrNumber *mapped_conkey, AttrNumber *confkey, Oid *conpfeqop)
Definition: tablecmds.c:8781
#define ERROR
Definition: elog.h:43
bool deferrable
Definition: parsenodes.h:2133
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:448
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5052
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3399
#define ereport(elevel, rest)
Definition: elog.h:141
#define AssertArg(condition)
Definition: c.h:734
List * lappend(List *list, void *datum)
Definition: list.c:128
ConstrType contype
Definition: tablecmds.c:184
AttrNumber * convert_tuples_by_name_map(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:246
void * palloc0(Size size)
Definition: mcxt.c:955
void CommandCounterIncrement(void)
Definition: xact.c:1003
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2175
char fk_del_action
Definition: parsenodes.h:2168
#define INDEX_MAX_KEYS
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4233
int errmsg(const char *fmt,...)
Definition: elog.c:784
int i
#define copyObject(obj)
Definition: nodes.h:640
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
bool skip_validation
Definition: parsenodes.h:2174
#define RelationGetRelid(relation)
Definition: rel.h:414
List * fk_attrs
Definition: parsenodes.h:2164
char fk_upd_action
Definition: parsenodes.h:2167
#define RelationGetPartitionDesc(relation)
Definition: rel.h:601
#define RelationGetNamespace(relation)
Definition: rel.h:455

◆ AlterIndexNamespaces()

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

Definition at line 14302 of file tablecmds.c.

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

Referenced by AlterTableNamespaceInternal().

14304 {
14305  List *indexList;
14306  ListCell *l;
14307 
14308  indexList = RelationGetIndexList(rel);
14309 
14310  foreach(l, indexList)
14311  {
14312  Oid indexOid = lfirst_oid(l);
14313  ObjectAddress thisobj;
14314 
14315  thisobj.classId = RelationRelationId;
14316  thisobj.objectId = indexOid;
14317  thisobj.objectSubId = 0;
14318 
14319  /*
14320  * Note: currently, the index will not have its own dependency on the
14321  * namespace, so we don't need to do changeDependencyFor(). There's no
14322  * row type in pg_type, either.
14323  *
14324  * XXX this objsMoved test may be pointless -- surely we have a single
14325  * dependency link from a relation to each index?
14326  */
14327  if (!object_address_present(&thisobj, objsMoved))
14328  {
14329  AlterRelationNamespaceInternal(classRel, indexOid,
14330  oldNspOid, newNspOid,
14331  false, objsMoved);
14332  add_exact_object_address(&thisobj, objsMoved);
14333  }
14334  }
14335 
14336  list_free(indexList);
14337 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2459
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2399
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:14232
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4342
void list_free(List *list)
Definition: list.c:1136
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 14232 of file tablecmds.c.

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

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

14236 {
14237  HeapTuple classTup;
14238  Form_pg_class classForm;
14239  ObjectAddress thisobj;
14240  bool already_done = false;
14241 
14242  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
14243  if (!HeapTupleIsValid(classTup))
14244  elog(ERROR, "cache lookup failed for relation %u", relOid);
14245  classForm = (Form_pg_class) GETSTRUCT(classTup);
14246 
14247  Assert(classForm->relnamespace == oldNspOid);
14248 
14249  thisobj.classId = RelationRelationId;
14250  thisobj.objectId = relOid;
14251  thisobj.objectSubId = 0;
14252 
14253  /*
14254  * If the object has already been moved, don't move it again. If it's
14255  * already in the right place, don't move it, but still fire the object
14256  * access hook.
14257  */
14258  already_done = object_address_present(&thisobj, objsMoved);
14259  if (!already_done && oldNspOid != newNspOid)
14260  {
14261  /* check for duplicate name (more friendly than unique-index failure) */
14262  if (get_relname_relid(NameStr(classForm->relname),
14263  newNspOid) != InvalidOid)
14264  ereport(ERROR,
14265  (errcode(ERRCODE_DUPLICATE_TABLE),
14266  errmsg("relation \"%s\" already exists in schema \"%s\"",
14267  NameStr(classForm->relname),
14268  get_namespace_name(newNspOid))));
14269 
14270  /* classTup is a copy, so OK to scribble on */
14271  classForm->relnamespace = newNspOid;
14272 
14273  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
14274 
14275  /* Update dependency on schema if caller said so */
14276  if (hasDependEntry &&
14277  changeDependencyFor(RelationRelationId,
14278  relOid,
14279  NamespaceRelationId,
14280  oldNspOid,
14281  newNspOid) != 1)
14282  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
14283  NameStr(classForm->relname));
14284  }
14285  if (!already_done)
14286  {
14287  add_exact_object_address(&thisobj, objsMoved);
14288 
14289  InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
14290  }
14291 
14292  heap_freetuple(classTup);
14293 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2459
int errcode(int sqlerrcode)
Definition: elog.c:570
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2399
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1687
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
int errmsg(const char *fmt,...)
Definition: elog.c:784
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:297
#define elog(elevel,...)
Definition: elog.h:226
#define NameStr(name)
Definition: c.h:609

◆ AlterSeqNamespaces()

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

Definition at line 14347 of file tablecmds.c.

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

Referenced by AlterTableNamespaceInternal().

14350 {
14351  Relation depRel;
14352  SysScanDesc scan;
14353  ScanKeyData key[2];
14354  HeapTuple tup;
14355 
14356  /*
14357  * SERIAL sequences are those having an auto dependency on one of the
14358  * table's columns (we don't care *which* column, exactly).
14359  */
14360  depRel = table_open(DependRelationId, AccessShareLock);
14361 
14362  ScanKeyInit(&key[0],
14363  Anum_pg_depend_refclassid,
14364  BTEqualStrategyNumber, F_OIDEQ,
14365  ObjectIdGetDatum(RelationRelationId));
14366  ScanKeyInit(&key[1],
14367  Anum_pg_depend_refobjid,
14368  BTEqualStrategyNumber, F_OIDEQ,
14370  /* we leave refobjsubid unspecified */
14371 
14372  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
14373  NULL, 2, key);
14374 
14375  while (HeapTupleIsValid(tup = systable_getnext(scan)))
14376  {
14377  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
14378  Relation seqRel;
14379 
14380  /* skip dependencies other than auto dependencies on columns */
14381  if (depForm->refobjsubid == 0 ||
14382  depForm->classid != RelationRelationId ||
14383  depForm->objsubid != 0 ||
14384  !(depForm->deptype == DEPENDENCY_AUTO || depForm->deptype == DEPENDENCY_INTERNAL))
14385  continue;
14386 
14387  /* Use relation_open just in case it's an index */
14388  seqRel = relation_open(depForm->objid, lockmode);
14389 
14390  /* skip non-sequence relations */
14391  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
14392  {
14393  /* No need to keep the lock */
14394  relation_close(seqRel, lockmode);
14395  continue;
14396  }
14397 
14398  /* Fix the pg_class and pg_depend entries */
14399  AlterRelationNamespaceInternal(classRel, depForm->objid,
14400  oldNspOid, newNspOid,
14401  true, objsMoved);
14402 
14403  /*
14404  * Sequences have entries in pg_type. We need to be careful to move
14405  * them to the new namespace, too.
14406  */
14408  newNspOid, false, false, objsMoved);
14409 
14410  /* Now we can close it. Keep the lock till end of transaction. */
14411  relation_close(seqRel, NoLock);
14412  }
14413 
14414  systable_endscan(scan);
14415 
14417 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define RelationGetForm(relation)
Definition: rel.h:408
#define DependReferenceIndexId
Definition: indexing.h:151
#define AccessShareLock
Definition: lockdefs.h:36
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3579
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
char relkind
Definition: pg_class.h:81
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:71
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:14232
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:414
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ AlterTable()

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

Definition at line 3480 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3481 {
3482  Relation rel;
3483 
3484  /* Caller is required to provide an adequate lock. */
3485  rel = relation_open(relid, NoLock);
3486 
3487  CheckTableNotInUse(rel, "ALTER TABLE");
3488 
3489  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode);
3490 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3810
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3399
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1753

◆ AlterTableGetLockLevel()

LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 3549 of file tablecmds.c.

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

3550 {
3551  /*
3552  * This only works if we read catalog tables using MVCC snapshots.
3553  */
3554  ListCell *lcmd;
3556 
3557  foreach(lcmd, cmds)
3558  {
3559  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3560  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
3561 
3562  switch (cmd->subtype)
3563  {
3564  /*
3565  * These subcommands rewrite the heap, so require full locks.
3566  */
3567  case AT_AddColumn: /* may rewrite heap, in some cases and visible
3568  * to SELECT */
3569  case AT_SetTableSpace: /* must rewrite heap */
3570  case AT_AlterColumnType: /* must rewrite heap */
3571  cmd_lockmode = AccessExclusiveLock;
3572  break;
3573 
3574  /*
3575  * These subcommands may require addition of toast tables. If
3576  * we add a toast table to a table currently being scanned, we
3577  * might miss data added to the new toast table by concurrent
3578  * insert transactions.
3579  */
3580  case AT_SetStorage: /* may add toast tables, see
3581  * ATRewriteCatalogs() */
3582  cmd_lockmode = AccessExclusiveLock;
3583  break;
3584 
3585  /*
3586  * Removing constraints can affect SELECTs that have been
3587  * optimized assuming the constraint holds true. See also
3588  * CloneFkReferenced.
3589  */
3590  case AT_DropConstraint: /* as DROP INDEX */
3591  case AT_DropNotNull: /* may change some SQL plans */
3592  cmd_lockmode = AccessExclusiveLock;
3593  break;
3594 
3595  /*
3596  * Subcommands that may be visible to concurrent SELECTs
3597  */
3598  case AT_DropColumn: /* change visible to SELECT */
3599  case AT_AddColumnToView: /* CREATE VIEW */
3600  case AT_DropOids: /* used to equiv to DropColumn */
3601  case AT_EnableAlwaysRule: /* may change SELECT rules */
3602  case AT_EnableReplicaRule: /* may change SELECT rules */
3603  case AT_EnableRule: /* may change SELECT rules */
3604  case AT_DisableRule: /* may change SELECT rules */
3605  cmd_lockmode = AccessExclusiveLock;
3606  break;
3607 
3608  /*
3609  * Changing owner may remove implicit SELECT privileges
3610  */
3611  case AT_ChangeOwner: /* change visible to SELECT */
3612  cmd_lockmode = AccessExclusiveLock;
3613  break;
3614 
3615  /*
3616  * Changing foreign table options may affect optimization.
3617  */
3618  case AT_GenericOptions:
3620  cmd_lockmode = AccessExclusiveLock;
3621  break;
3622 
3623  /*
3624  * These subcommands affect write operations only.
3625  */
3626  case AT_EnableTrig:
3627  case AT_EnableAlwaysTrig:
3628  case AT_EnableReplicaTrig:
3629  case AT_EnableTrigAll:
3630  case AT_EnableTrigUser:
3631  case AT_DisableTrig:
3632  case AT_DisableTrigAll:
3633  case AT_DisableTrigUser:
3634  cmd_lockmode = ShareRowExclusiveLock;
3635  break;
3636 
3637  /*
3638  * These subcommands affect write operations only. XXX
3639  * Theoretically, these could be ShareRowExclusiveLock.
3640  */
3641  case AT_ColumnDefault:
3642  case AT_AlterConstraint:
3643  case AT_AddIndex: /* from ADD CONSTRAINT */
3644  case AT_AddIndexConstraint:
3645  case AT_ReplicaIdentity:
3646  case AT_SetNotNull:
3647  case AT_EnableRowSecurity:
3648  case AT_DisableRowSecurity:
3649  case AT_ForceRowSecurity:
3650  case AT_NoForceRowSecurity:
3651  case AT_AddIdentity:
3652  case AT_DropIdentity:
3653  case AT_SetIdentity:
3654  cmd_lockmode = AccessExclusiveLock;
3655  break;
3656 
3657  case AT_AddConstraint:
3658  case AT_ProcessedConstraint: /* becomes AT_AddConstraint */
3659  case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
3660  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
3661  case AT_ReAddDomainConstraint: /* becomes AT_AddConstraint */
3662  if (IsA(cmd->def, Constraint))
3663  {
3664  Constraint *con = (Constraint *) cmd->def;
3665 
3666  switch (con->contype)
3667  {
3668  case CONSTR_EXCLUSION:
3669  case CONSTR_PRIMARY:
3670  case CONSTR_UNIQUE:
3671 
3672  /*
3673  * Cases essentially the same as CREATE INDEX. We
3674  * could reduce the lock strength to ShareLock if
3675  * we can work out how to allow concurrent catalog
3676  * updates. XXX Might be set down to
3677  * ShareRowExclusiveLock but requires further
3678  * analysis.
3679  */
3680  cmd_lockmode = AccessExclusiveLock;
3681  break;
3682  case CONSTR_FOREIGN:
3683 
3684  /*
3685  * We add triggers to both tables when we add a
3686  * Foreign Key, so the lock level must be at least
3687  * as strong as CREATE TRIGGER.
3688  */
3689  cmd_lockmode = ShareRowExclusiveLock;
3690  break;
3691 
3692  default:
3693  cmd_lockmode = AccessExclusiveLock;
3694  }
3695  }
3696  break;
3697 
3698  /*
3699  * These subcommands affect inheritance behaviour. Queries
3700  * started before us will continue to see the old inheritance
3701  * behaviour, while queries started after we commit will see
3702  * new behaviour. No need to prevent reads or writes to the
3703  * subtable while we hook it up though. Changing the TupDesc
3704  * may be a problem, so keep highest lock.
3705  */
3706  case AT_AddInherit:
3707  case AT_DropInherit:
3708  cmd_lockmode = AccessExclusiveLock;
3709  break;
3710 
3711  /*
3712  * These subcommands affect implicit row type conversion. They
3713  * have affects similar to CREATE/DROP CAST on queries. don't
3714  * provide for invalidating parse trees as a result of such
3715  * changes, so we keep these at AccessExclusiveLock.
3716  */
3717  case AT_AddOf:
3718  case AT_DropOf:
3719  cmd_lockmode = AccessExclusiveLock;
3720  break;
3721 
3722  /*
3723  * Only used by CREATE OR REPLACE VIEW which must conflict
3724  * with an SELECTs currently using the view.
3725  */
3726  case AT_ReplaceRelOptions:
3727  cmd_lockmode = AccessExclusiveLock;
3728  break;
3729 
3730  /*
3731  * These subcommands affect general strategies for performance
3732  * and maintenance, though don't change the semantic results
3733  * from normal data reads and writes. Delaying an ALTER TABLE
3734  * behind currently active writes only delays the point where
3735  * the new strategy begins to take effect, so there is no
3736  * benefit in waiting. In this case the minimum restriction
3737  * applies: we don't currently allow concurrent catalog
3738  * updates.
3739  */
3740  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
3741  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
3742  case AT_DropCluster: /* Uses MVCC in getIndexes() */
3743  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
3744  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
3745  cmd_lockmode = ShareUpdateExclusiveLock;
3746  break;
3747 
3748  case AT_SetLogged:
3749  case AT_SetUnLogged:
3750  cmd_lockmode = AccessExclusiveLock;
3751  break;
3752 
3753  case AT_ValidateConstraint: /* Uses MVCC in getConstraints() */
3754  cmd_lockmode = ShareUpdateExclusiveLock;
3755  break;
3756 
3757  /*
3758  * Rel options are more complex than first appears. Options
3759  * are set here for tables, views and indexes; for historical
3760  * reasons these can all be used with ALTER TABLE, so we can't
3761  * decide between them using the basic grammar.
3762  */
3763  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
3764  * getTables() */
3765  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
3766  * getTables() */
3767  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
3768  break;
3769 
3770  case AT_AttachPartition:
3771  cmd_lockmode = ShareUpdateExclusiveLock;
3772  break;
3773 
3774  case AT_DetachPartition:
3775  cmd_lockmode = AccessExclusiveLock;
3776  break;
3777 
3778  case AT_CheckNotNull:
3779 
3780  /*
3781  * This only examines the table's schema; but lock must be
3782  * strong enough to prevent concurrent DROP NOT NULL.
3783  */
3784  cmd_lockmode = AccessShareLock;
3785  break;
3786 
3787  default: /* oops */
3788  elog(ERROR, "unrecognized alter table type: %d",
3789  (int) cmd->subtype);
3790  break;
3791  }
3792 
3793  /*
3794  * Take the greatest lockmode from any subcommand
3795  */
3796  if (cmd_lockmode > lockmode)
3797  lockmode = cmd_lockmode;
3798  }
3799 
3800  return lockmode;
3801 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:575
int LOCKMODE
Definition: lockdefs.h:26
#define AccessShareLock
Definition: lockdefs.h:36
AlterTableType subtype
Definition: parsenodes.h:1840
#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:1589
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define elog(elevel,...)
Definition: elog.h:226
ConstrType contype
Definition: parsenodes.h:2129
Definition: pg_list.h:45

◆ AlterTableInternal()

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

Definition at line 3504 of file tablecmds.c.

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

Referenced by AlterTableMoveAll(), and DefineVirtualRelation().

3505 {
3506  Relation rel;
3507  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
3508 
3509  rel = relation_open(relid, lockmode);
3510 
3512 
3513  ATController(NULL, rel, cmds, recurse, lockmode);
3514 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3810
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:3549
void EventTriggerAlterTableRelid(Oid objectId)

◆ AlterTableLookupRelation()

Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 3429 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3430 {
3431  return RangeVarGetRelidExtended(stmt->relation, lockmode,
3432  stmt->missing_ok ? RVR_MISSING_OK : 0,
3434  (void *) stmt);
3435 }
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:14760
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:228
RangeVar * relation
Definition: parsenodes.h:1753

◆ AlterTableMoveAll()

Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 12427 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

12428 {
12429  List *relations = NIL;
12430  ListCell *l;
12431  ScanKeyData key[1];
12432  Relation rel;
12433  TableScanDesc scan;
12434  HeapTuple tuple;
12435  Oid orig_tablespaceoid;
12436  Oid new_tablespaceoid;
12437  List *role_oids = roleSpecsToIds(stmt->roles);
12438 
12439  /* Ensure we were not asked to move something we can't */
12440  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
12441  stmt->objtype != OBJECT_MATVIEW)
12442  ereport(ERROR,
12443  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
12444  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
12445 
12446  /* Get the orig and new tablespace OIDs */
12447  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
12448  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
12449 
12450  /* Can't move shared relations in to or out of pg_global */
12451  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
12452  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
12453  new_tablespaceoid == GLOBALTABLESPACE_OID)
12454  ereport(ERROR,
12455  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
12456  errmsg("cannot move relations in to or out of pg_global tablespace")));
12457 
12458  /*
12459  * Must have CREATE rights on the new tablespace, unless it is the
12460  * database default tablespace (which all users implicitly have CREATE
12461  * rights on).
12462  */
12463  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
12464  {
12465  AclResult aclresult;
12466 
12467  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
12468  ACL_CREATE);
12469  if (aclresult != ACLCHECK_OK)
12470  aclcheck_error(aclresult, OBJECT_TABLESPACE,
12471  get_tablespace_name(new_tablespaceoid));
12472  }
12473 
12474  /*
12475  * Now that the checks are done, check if we should set either to
12476  * InvalidOid because it is our database's default tablespace.
12477  */
12478  if (orig_tablespaceoid == MyDatabaseTableSpace)
12479  orig_tablespaceoid = InvalidOid;
12480 
12481  if (new_tablespaceoid == MyDatabaseTableSpace)
12482  new_tablespaceoid = InvalidOid;
12483 
12484  /* no-op */
12485  if (orig_tablespaceoid == new_tablespaceoid)
12486  return new_tablespaceoid;
12487 
12488  /*
12489  * Walk the list of objects in the tablespace and move them. This will
12490  * only find objects in our database, of course.
12491  */
12492  ScanKeyInit(&key[0],
12493  Anum_pg_class_reltablespace,
12494  BTEqualStrategyNumber, F_OIDEQ,
12495  ObjectIdGetDatum(orig_tablespaceoid));
12496 
12497  rel = table_open(RelationRelationId, AccessShareLock);
12498  scan = table_beginscan_catalog(rel, 1, key);
12499  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
12500  {
12501  Form_pg_class relForm = (Form_pg_class) GETSTRUCT(tuple);
12502  Oid relOid = relForm->oid;
12503 
12504  /*
12505  * Do not move objects in pg_catalog as part of this, if an admin
12506  * really wishes to do so, they can issue the individual ALTER
12507  * commands directly.
12508  *
12509  * Also, explicitly avoid any shared tables, temp tables, or TOAST
12510  * (TOAST will be moved with the main table).
12511  */
12512  if (IsCatalogNamespace(relForm->relnamespace) ||
12513  relForm->relisshared ||
12514  isAnyTempNamespace(relForm->relnamespace) ||
12515  IsToastNamespace(relForm->relnamespace))
12516  continue;
12517 
12518  /* Only move the object type requested */
12519  if ((stmt->objtype == OBJECT_TABLE &&
12520  relForm->relkind != RELKIND_RELATION &&
12521  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
12522  (stmt->objtype == OBJECT_INDEX &&
12523  relForm->relkind != RELKIND_INDEX &&
12524  relForm->relkind != RELKIND_PARTITIONED_INDEX) ||
12525  (stmt->objtype == OBJECT_MATVIEW &&
12526  relForm->relkind != RELKIND_MATVIEW))
12527  continue;
12528 
12529  /* Check if we are only moving objects owned by certain roles */
12530  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
12531  continue;
12532 
12533  /*
12534  * Handle permissions-checking here since we are locking the tables
12535  * and also to avoid doing a bunch of work only to fail part-way. Note
12536  * that permissions will also be checked by AlterTableInternal().
12537  *
12538  * Caller must be considered an owner on the table to move it.
12539  */
12540  if (!pg_class_ownercheck(relOid, GetUserId()))
12542  NameStr(relForm->relname));
12543 
12544  if (stmt->nowait &&
12546  ereport(ERROR,
12547  (errcode(ERRCODE_OBJECT_IN_USE),
12548  errmsg("aborting because lock on relation \"%s.%s\" is not available",
12549  get_namespace_name(relForm->relnamespace),
12550  NameStr(relForm->relname))));
12551  else
12553 
12554  /* Add to our list of objects to move */
12555  relations = lappend_oid(relations, relOid);
12556  }
12557 
12558  table_endscan(scan);
12560 
12561  if (relations == NIL)
12562  ereport(NOTICE,
12563  (errcode(ERRCODE_NO_DATA_FOUND),
12564  errmsg("no matching relations in tablespace \"%s\" found",
12565  orig_tablespaceoid == InvalidOid ? "(database default)" :
12566  get_tablespace_name(orig_tablespaceoid))));
12567 
12568  /* Everything is locked, loop through and move all of the relations. */
12569  foreach(l, relations)
12570  {
12571  List *cmds = NIL;
12573 
12574  cmd->subtype = AT_SetTableSpace;
12575  cmd->name = stmt->new_tablespacename;
12576 
12577  cmds = lappend(cmds, cmd);
12578 
12580  /* OID is set by AlterTableInternal */
12581  AlterTableInternal(lfirst_oid(l), cmds, false);
12583  }
12584 
12585  return new_tablespaceoid;
12586 }
#define NIL
Definition: pg_list.h:69
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:151
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1399
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4705
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:94
Oid GetUserId(void)
Definition: miscinit.c:380
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:524
int errcode(int sqlerrcode)
Definition: elog.c:570
AlterTableType subtype
Definition: parsenodes.h:1840
bool IsToastNamespace(Oid namespaceId)
Definition: catalog.c:197
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:638
Oid MyDatabaseTableSpace
Definition: globals.c:87
void EventTriggerAlterTableStart(Node *parsetree)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3353
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1290
#define ereport(elevel, rest)
Definition: elog.h:141
List * lappend(List *list, void *datum)
Definition: list.c:128
AclResult
Definition: acl.h:178
#define InvalidOid
Definition: postgres_ext.h:36
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:572
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1405
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:4755
bool IsCatalogNamespace(Oid namespaceId)
Definition: catalog.c:179
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:831
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:3504
#define AccessExclusiveLock
Definition: lockdefs.h:45
int errmsg(const char *fmt,...)
Definition: elog.c:784
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1445
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:609
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3174
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h: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 14123 of file tablecmds.c.

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

Referenced by ExecAlterObjectSchemaStmt().

14124 {
14125  Relation rel;
14126  Oid relid;
14127  Oid oldNspOid;
14128  Oid nspOid;
14129  RangeVar *newrv;
14130  ObjectAddresses *objsMoved;
14131  ObjectAddress myself;
14132 
14134  stmt->missing_ok ? RVR_MISSING_OK : 0,
14136  (void *) stmt);
14137 
14138  if (!OidIsValid(relid))
14139  {
14140  ereport(NOTICE,
14141  (errmsg("relation \"%s\" does not exist, skipping",
14142  stmt->relation->relname)));
14143  return InvalidObjectAddress;
14144  }
14145 
14146  rel = relation_open(relid, NoLock);
14147 
14148  oldNspOid = RelationGetNamespace(rel);
14149 
14150  /* If it's an owned sequence, disallow moving it by itself. */
14151  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
14152  {
14153  Oid tableId;
14154  int32 colId;
14155 
14156  if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
14157  sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
14158  ereport(ERROR,
14159  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
14160  errmsg("cannot move an owned sequence into another schema"),
14161  errdetail("Sequence \"%s\" is linked to table \"%s\".",
14163  get_rel_name(tableId))));
14164  }
14165 
14166  /* Get and lock schema OID and check its permissions. */
14167  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
14168  nspOid = RangeVarGetAndCheckCreationNamespace(newrv, NoLock, NULL);
14169 
14170  /* common checks on switching namespaces */
14171  CheckSetNamespace(oldNspOid, nspOid);
14172 
14173  objsMoved = new_object_addresses();
14174  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
14175  free_object_addresses(objsMoved);
14176 
14177  ObjectAddressSet(myself, RelationRelationId, relid);
14178 
14179  if (oldschema)
14180  *oldschema = oldNspOid;
14181 
14182  /* close rel, but keep lock until commit */
14183  relation_close(rel, NoLock);
14184 
14185  return myself;
14186 }
bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
Definition: pg_depend.c:663
int errcode(int sqlerrcode)
Definition: elog.c:570
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2344
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2639
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:638
signed int int32
Definition: c.h:346
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:43
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:14194
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:14760
int errdetail(const char *fmt,...)
Definition: elog.c:860
#define RelationGetRelationName(relation)
Definition: rel.h:448
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:228
#define ereport(elevel, rest)
Definition: elog.h:141
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2946
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:526
#define NOTICE
Definition: elog.h:37
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define AccessExclusiveLock
Definition: lockdefs.h:45
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:784
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:421
#define RelationGetNamespace(relation)
Definition: rel.h:455

◆ AlterTableNamespaceInternal()

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

Definition at line 14194 of file tablecmds.c.

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

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

14196 {
14197  Relation classRel;
14198 
14199  Assert(objsMoved != NULL);
14200 
14201  /* OK, modify the pg_class row and pg_depend entry */
14202  classRel = table_open(RelationRelationId, RowExclusiveLock);
14203 
14204  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
14205  nspOid, true, objsMoved);
14206 
14207  /* Fix the table's row type too */
14208  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
14209  nspOid, false, false, objsMoved);
14210 
14211  /* Fix other dependent stuff */
14212  if (rel->rd_rel->relkind == RELKIND_RELATION ||
14213  rel->rd_rel->relkind == RELKIND_MATVIEW ||
14214  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
14215  {
14216  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
14217  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
14218  objsMoved, AccessExclusiveLock);
14219  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
14220  false, objsMoved);
14221  }
14222 
14223  table_close(classRel, RowExclusiveLock);
14224 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3579
Form_pg_class rd_rel
Definition: rel.h:84
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:14302
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:14347
#define RowExclusiveLock
Definition: lockdefs.h:38
#define Assert(condition)
Definition: c.h:732
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:14232
#define AccessExclusiveLock
Definition: lockdefs.h:45
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define RelationGetRelid(relation)
Definition: rel.h:414

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

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

Referenced by ATExecAddConstraint().

7410 {
7411  List *newcons;
7412  ListCell *lcon;
7413  List *children;
7414  ListCell *child;
7416 
7417  /* At top level, permission check was done in ATPrepCmd, else do it */
7418  if (recursing)
7420 
7421  /*
7422  * Call AddRelationNewConstraints to do the work, making sure it works on
7423  * a copy of the Constraint so transformExpr can't modify the original. It
7424  * returns a list of cooked constraints.
7425  *
7426  * If the constraint ends up getting merged with a pre-existing one, it's
7427  * omitted from the returned list, which is what we want: we do not need
7428  * to do any validation work. That can only happen at child tables,
7429  * though, since we disallow merging at the top level.
7430  */
7431  newcons = AddRelationNewConstraints(rel, NIL,
7432  list_make1(copyObject(constr)),
7433  recursing | is_readd, /* allow_merge */
7434  !recursing, /* is_local */
7435  is_readd, /* is_internal */
7436  NULL); /* queryString not available
7437  * here */
7438 
7439  /* we don't expect more than one constraint here */
7440  Assert(list_length(newcons) <= 1);
7441 
7442  /* Add each to-be-validated constraint to Phase 3's queue */
7443  foreach(lcon, newcons)
7444  {
7445  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
7446 
7447  if (!ccon->skip_validation)
7448  {
7449  NewConstraint *newcon;
7450 
7451  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
7452  newcon->name = ccon->name;
7453  newcon->contype = ccon->contype;
7454  newcon->qual = ccon->expr;
7455 
7456  tab->constraints = lappend(tab->constraints, newcon);
7457  }
7458 
7459  /* Save the actually assigned name if it was defaulted */
7460  if (constr->conname == NULL)
7461  constr->conname = ccon->name;
7462 
7463  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
7464  }
7465 
7466  /* At this point we must have a locked-down name to use */
7467  Assert(constr->conname != NULL);
7468 
7469  /* Advance command counter in case same table is visited multiple times */
7471 
7472  /*
7473  * If the constraint got merged with an existing constraint, we're done.
7474  * We mustn't recurse to child tables in this case, because they've
7475  * already got the constraint, and visiting them again would lead to an
7476  * incorrect value for coninhcount.
7477  */
7478  if (newcons == NIL)
7479  return address;
7480 
7481  /*
7482  * If adding a NO INHERIT constraint, no need to find our children.
7483  */
7484  if (constr->is_no_inherit)
7485  return address;
7486 
7487  /*
7488  * Propagate to children as appropriate. Unlike most other ALTER
7489  * routines, we have to do this one level of recursion at a time; we can't
7490  * use find_all_inheritors to do it in one pass.
7491  */
7492  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
7493 
7494  /*
7495  * Check if ONLY was specified with ALTER TABLE. If so, allow the
7496  * constraint creation only if there are no children currently. Error out
7497  * otherwise.
7498  */
7499  if (!recurse && children != NIL)
7500  ereport(ERROR,
7501  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7502  errmsg("constraint must be added to child tables too")));
7503 
7504  foreach(child, children)
7505  {
7506  Oid childrelid = lfirst_oid(child);
7507  Relation childrel;
7508  AlteredTableInfo *childtab;
7509 
7510  /* find_inheritance_children already got lock */
7511  childrel = table_open(childrelid, NoLock);
7512  CheckTableNotInUse(childrel, "ALTER TABLE");
7513 
7514  /* Find or create work queue entry for this table */
7515  childtab = ATGetQueueEntry(wqueue, childrel);
7516 
7517  /* Recurse to child */
7518  ATAddCheckConstraint(wqueue, childtab, childrel,
7519  constr, recurse, true, is_readd, lockmode);
7520 
7521  table_close(childrel, NoLock);
7522  }
7523 
7524  return address;
7525 }
#define NIL
Definition: pg_list.h:69
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2492
char * name
Definition: tablecmds.c:183
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
Node * qual
Definition: tablecmds.c:188
int errcode(int sqlerrcode)
Definition: elog.c:570
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:7407
char * conname
Definition: parsenodes.h:2132
unsigned int Oid
Definition: postgres_ext.h:31
#define ATT_TABLE
Definition: tablecmds.c:286
List * constraints
Definition: tablecmds.c:162
#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:5052
bool skip_validation
Definition: heap.h:41
ConstrType contype
Definition: heap.h:36
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3399
#define ereport(elevel, rest)
Definition: elog.h:141
List * lappend(List *list, void *datum)
Definition: list.c:128
ConstrType contype
Definition: tablecmds.c:184
void * palloc0(Size size)
Definition: mcxt.c:955
void CommandCounterIncrement(void)
Definition: xact.c:1003
bool is_no_inherit
Definition: parsenodes.h:2138
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:55
#define Assert(condition)
Definition: c.h:732
#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:784
Oid conoid
Definition: heap.h:37
Node * expr
Definition: heap.h:40
static void ATSimplePermissions(Relation rel, int allowed_targets)
Definition: tablecmds.c:5089
#define copyObject(obj)
Definition: nodes.h:640
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:45
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:291
char * name
Definition: heap.h:38
#define RelationGetRelid(relation)
Definition: rel.h:414
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ ATAddForeignKeyConstraint()

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

Definition at line 7543 of file tablecmds.c.

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

Referenced by ATExecAddConstraint().

7546 {
7547  Relation pkrel;
7548  int16 pkattnum[INDEX_MAX_KEYS];
7549  int16 fkattnum[INDEX_MAX_KEYS];
7550  Oid pktypoid[INDEX_MAX_KEYS];
7551  Oid fktypoid[INDEX_MAX_KEYS];
7552  Oid opclasses[INDEX_MAX_KEYS];
7553  Oid pfeqoperators[INDEX_MAX_KEYS];
7554  Oid ppeqoperators[INDEX_MAX_KEYS];
7555  Oid ffeqoperators[INDEX_MAX_KEYS];
7556  int i;
7557  int numfks,
7558  numpks;
7559  Oid indexOid;
7560  bool old_check_ok;
7561  ObjectAddress address;
7562  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
7563 
7564  /*
7565  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
7566  * delete rows out from under us.
7567  */
7568  if (OidIsValid(fkconstraint->old_pktable_oid))
7569  pkrel = table_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
7570  else
7571  pkrel = table_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
7572 
7573  /*
7574  * Validity checks (permission checks wait till we have the column
7575  * numbers)
7576  */
7577  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7578  {
7579  if (!recurse)
7580  ereport(ERROR,
7581  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7582  errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
7584  RelationGetRelationName(pkrel))));
7585  if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
7586  ereport(ERROR,
7587  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7588  errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
7590  RelationGetRelationName(pkrel)),
7591  errdetail("This feature is not yet supported on partitioned tables.")));
7592  }
7593 
7594  if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
7595  pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
7596  ereport(ERROR,
7597  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
7598  errmsg("referenced relation \"%s\" is not a table",
7599  RelationGetRelationName(pkrel))));
7600 
7601  if (!allowSystemTableMods && IsSystemRelation(pkrel))
7602  ereport(ERROR,
7603  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
7604  errmsg("permission denied: \"%s\" is a system catalog",
7605  RelationGetRelationName(pkrel))));
7606 
7607  /*
7608  * References from permanent or unlogged tables to temp tables, and from
7609  * permanent tables to unlogged tables, are disallowed because the
7610  * referenced data can vanish out from under us. References from temp
7611  * tables to any other table type are also disallowed, because other
7612  * backends might need to run the RI triggers on the perm table, but they
7613  * can't reliably see tuples in the local buffers of other backends.
7614  */
7615  switch (rel->rd_rel->relpersistence)
7616  {
7617  case RELPERSISTENCE_PERMANENT:
7618  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
7619  ereport(ERROR,
7620  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7621  errmsg("constraints on permanent tables may reference only permanent tables")));
7622  break;
7623  case RELPERSISTENCE_UNLOGGED:
7624  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT
7625  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
7626  ereport(ERROR,
7627  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7628  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
7629  break;
7630  case RELPERSISTENCE_TEMP:
7631  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
7632  ereport(ERROR,
7633  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7634  errmsg("constraints on temporary tables may reference only temporary tables")));
7635  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
7636  ereport(ERROR,
7637  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
7638  errmsg("constraints on temporary tables must involve temporary tables of this session")));
7639  break;
7640  }
7641 
7642  /*
7643  * Look up the referencing attributes to make sure they exist, and record
7644  * their attnums and type OIDs.
7645  */
7646  MemSet(pkattnum, 0, sizeof(pkattnum));
7647  MemSet(fkattnum, 0, sizeof(fkattnum));
7648  MemSet(pktypoid, 0, sizeof(pktypoid));
7649  MemSet(fktypoid, 0, sizeof(fktypoid));
7650  MemSet(opclasses, 0, sizeof(opclasses));
7651  MemSet(pfeqoperators, 0, sizeof(pfeqoperators));
7652  MemSet(ppeqoperators, 0, sizeof(ppeqoperators));
7653  MemSet(ffeqoperators, 0, sizeof(ffeqoperators));
7654 
7656  fkconstraint->fk_attrs,
7657  fkattnum, fktypoid);
7658 
7659  /*
7660  * If the attribute list for the referenced table was omitted, lookup the
7661  * definition of the primary key and use it. Otherwise, validate the
7662  * supplied attribute list. In either case, discover the index OID and
7663  * index opclasses, and the attnums and type OIDs of the attributes.
7664  */
7665  if (fkconstraint->pk_attrs == NIL)
7666  {
7667  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
7668  &fkconstraint->pk_attrs,
7669  pkattnum, pktypoid,
7670  opclasses);
7671  }
7672  else
7673  {
7674  numpks = transformColumnNameList(RelationGetRelid(pkrel),
7675  fkconstraint->pk_attrs,
7676  pkattnum, pktypoid);
7677  /* Look for an index matching the column list */
7678  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
7679  opclasses);
7680  }
7681 
7682  /*
7683  * Now we can check permissions.
7684  */
7685  checkFkeyPermissions(pkrel, pkattnum, numpks);
7686 
7687  /*
7688  * Check some things for generated columns.
7689  */
7690  for (i = 0; i < numfks; i++)
7691  {
7692  char attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
7693 
7694  if (attgenerated)
7695  {
7696  /*
7697  * Check restrictions on UPDATE/DELETE actions, per SQL standard
7698  */
7699  if (fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETNULL ||
7700  fkconstraint->fk_upd_action == FKCONSTR_ACTION_SETDEFAULT ||
7701  fkconstraint->fk_upd_action == FKCONSTR_ACTION_CASCADE)
7702  ereport(ERROR,
7703  (errcode(ERRCODE_SYNTAX_ERROR),
7704  errmsg("invalid %s action for foreign key constraint containing generated column",
7705  "ON UPDATE")));
7706  if (fkconstraint->fk_del_action == FKCONSTR_ACTION_SETNULL ||
7707  fkconstraint->fk_del_action == FKCONSTR_ACTION_SETDEFAULT)
7708  ereport(ERROR,
7709  (errcode(ERRCODE_SYNTAX_ERROR),
7710  errmsg("invalid %s action for foreign key constraint containing generated column",
7711  "ON DELETE")));
7712  }
7713  }
7714 
7715  /*
7716  * Look up the equality operators to use in the constraint.
7717  *
7718  * Note that we have to be careful about the difference between the actual
7719  * PK column type and the opclass' declared input type, which might be
7720  * only binary-compatible with it. The declared opcintype is the right
7721  * thing to probe pg_amop with.
7722  */
7723  if (numfks != numpks)
7724  ereport(ERROR,
7725  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
7726  errmsg("number of referencing and referenced columns for foreign key disagree")));
7727 
7728  /*
7729  * On the strength of a previous constraint, we might avoid scanning
7730  * tables to validate this one. See below.
7731  */
7732  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
7733  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
7734 
7735  for (i = 0; i < numpks; i++)
7736  {
7737  Oid pktype = pktypoid[i];
7738  Oid fktype = fktypoid[i];
7739  Oid fktyped;
7740  HeapTuple cla_ht;
7741  Form_pg_opclass cla_tup;
7742  Oid amid;
7743  Oid opfamily;
7744  Oid opcintype;
7745  Oid pfeqop;
7746  Oid ppeqop;
7747  Oid ffeqop;
7748  int16 eqstrategy;
7749  Oid pfeqop_right;
7750 
7751  /* We need several fields out of the pg_opclass entry */
7752  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
7753  if (!HeapTupleIsValid(cla_ht))
7754  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
7755  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
7756  amid = cla_tup->opcmethod;
7757  opfamily = cla_tup->opcfamily;
7758  opcintype = cla_tup->opcintype;
7759  ReleaseSysCache(cla_ht);
7760 
7761  /*
7762  * Check it's a btree; currently this can never fail since no other
7763  * index AMs support unique indexes. If we ever did have other types
7764  * of unique indexes, we'd need a way to determine which operator
7765  * strategy number is equality. (Is it reasonable to insist that
7766  * every such index AM use btree's number for equality?)
7767  */
7768  if (amid != BTREE_AM_OID)
7769  elog(ERROR, "only b-tree indexes are supported for foreign keys");
7770  eqstrategy = BTEqualStrategyNumber;
7771 
7772  /*
7773  * There had better be a primary equality operator for the index.
7774  * We'll use it for PK = PK comparisons.
7775  */
7776  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
7777  eqstrategy);
7778 
7779  if (!OidIsValid(ppeqop))
7780  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
7781  eqstrategy, opcintype, opcintype, opfamily);
7782 
7783  /*
7784  * Are there equality operators that take exactly the FK type? Assume
7785  * we should look through any domain here.
7786  */
7787  fktyped = getBaseType(fktype);
7788 
7789  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
7790  eqstrategy);
7791  if (OidIsValid(pfeqop))
7792  {
7793  pfeqop_right = fktyped;
7794  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
7795  eqstrategy);
7796  }
7797  else
7798  {
7799  /* keep compiler quiet */
7800  pfeqop_right = InvalidOid;
7801  ffeqop = InvalidOid;
7802  }
7803 
7804  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
7805  {
7806  /*
7807  * Otherwise, look for an implicit cast from the FK type to the
7808  * opcintype, and if found, use the primary equality operator.
7809  * This is a bit tricky because opcintype might be a polymorphic
7810  * type such as ANYARRAY or ANYENUM; so what we have to test is
7811  * whether the two actual column types can be concurrently cast to
7812  * that type. (Otherwise, we'd fail to reject combinations such
7813  * as int[] and point[].)
7814  */
7815  Oid input_typeids[2];
7816  Oid target_typeids[2];
7817 
7818  input_typeids[0] = pktype;
7819  input_typeids[1] = fktype;
7820  target_typeids[0] = opcintype;
7821  target_typeids[1] = opcintype;
7822  if (can_coerce_type(2, input_typeids, target_typeids,
7824  {
7825  pfeqop = ffeqop = ppeqop;
7826  pfeqop_right = opcintype;
7827  }
7828  }
7829 
7830  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
7831  ereport(ERROR,
7832  (errcode(ERRCODE_DATATYPE_MISMATCH),
7833  errmsg("foreign key constraint \"%s\" cannot be implemented",
7834  fkconstraint->conname),
7835  errdetail("Key columns \"%s\" and \"%s\" "
7836  "are of incompatible types: %s and %s.",
7837  strVal(list_nth(fkconstraint->fk_attrs, i)),
7838  strVal(list_nth(fkconstraint->pk_attrs, i)),
7839  format_type_be(fktype),
7840  format_type_be(pktype))));
7841 
7842  if (old_check_ok)
7843  {
7844  /*
7845  * When a pfeqop changes, revalidate the constraint. We could
7846  * permit intra-opfamily changes, but that adds subtle complexity
7847  * without any concrete benefit for core types. We need not
7848  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
7849  */
7850  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
7851  old_pfeqop_item = lnext(old_pfeqop_item);
7852  }
7853  if (old_check_ok)
7854  {
7855  Oid old_fktype;
7856  Oid new_fktype;
7857  CoercionPathType old_pathtype;
7858  CoercionPathType new_pathtype;
7859  Oid old_castfunc;
7860  Oid new_castfunc;
7862  fkattnum[i] - 1);
7863 
7864  /*
7865  * Identify coercion pathways from each of the old and new FK-side
7866  * column types to the right (foreign) operand type of the pfeqop.
7867  * We may assume that pg_constraint.conkey is not changing.
7868  */
7869  old_fktype = attr->atttypid;
7870  new_fktype = fktype;
7871  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
7872  &old_castfunc);
7873  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
7874  &new_castfunc);
7875 
7876  /*
7877  * Upon a change to the cast from the FK column to its pfeqop
7878  * operand, revalidate the constraint. For this evaluation, a
7879  * binary coercion cast is equivalent to no cast at all. While
7880  * type implementors should design implicit casts with an eye
7881  * toward consistency of operations like equality, we cannot
7882  * assume here that they have done so.
7883  *
7884  * A function with a polymorphic argument could change behavior
7885  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
7886  * when the cast destination is polymorphic, we only avoid
7887  * revalidation if the input type has not changed at all. Given
7888  * just the core data types and operator classes, this requirement
7889  * prevents no would-be optimizations.
7890  *
7891  * If the cast converts from a base type to a domain thereon, then
7892  * that domain type must be the opcintype of the unique index.
7893  * Necessarily, the primary key column must then be of the domain
7894  * type. Since the constraint was previously valid, all values on
7895  * the foreign side necessarily exist on the primary side and in
7896  * turn conform to the domain. Consequently, we need not treat
7897  * domains specially here.
7898  *
7899  * Since we require that all collations share the same notion of
7900  * equality (which they do, because texteq reduces to bitwise
7901  * equality), we don't compare collation here.
7902  *
7903  * We need not directly consider the PK type. It's necessarily
7904  * binary coercible to the opcintype of the unique index column,
7905  * and ri_triggers.c will only deal with PK datums in terms of
7906  * that opcintype. Changing the opcintype also changes pfeqop.
7907  */
7908  old_check_ok = (new_pathtype == old_pathtype &&
7909  new_castfunc == old_castfunc &&
7910  (!IsPolymorphicType(pfeqop_right) ||
7911  new_fktype == old_fktype));
7912 
7913  }
7914 
7915  pfeqoperators[i] = pfeqop;
7916  ppeqoperators[i] = ppeqop;
7917  ffeqoperators[i] = ffeqop;
7918  }
7919 
7920  /*
7921  * Create all the constraint and trigger objects, recursing to partitions
7922  * as necessary. First handle the referenced side.
7923  */
7924  address = addFkRecurseReferenced(wqueue, fkconstraint, rel, pkrel,
7925  indexOid,
7926  InvalidOid, /* no parent constraint */
7927  numfks,
7928  pkattnum,
7929  fkattnum,
7930  pfeqoperators,
7931  ppeqoperators,
7932  ffeqoperators,
7933  old_check_ok);
7934 
7935  /* Now handle the referencing side. */
7936  addFkRecurseReferencing(wqueue, fkconstraint, rel, pkrel,
7937  indexOid,
7938  address.objectId,
7939  numfks,
7940  pkattnum,
7941  fkattnum,
7942  pfeqoperators,
7943  ppeqoperators,
7944  ffeqoperators,
7945  old_check_ok,
7946  lockmode);
7947 
7948  /*
7949  * Done. Close pk table, but keep lock until we've committed.
7950  */
7951  table_close(pkrel, NoLock);
7952 
7953  return address;
7954 }
signed short int16
Definition: c.h:345
#define NIL
Definition: pg_list.h:69
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
List * old_conpfeqop
Definition: parsenodes.h:2169
bool IsSystemRelation(Relation relation)
Definition: catalog.c:70
#define RelationGetDescr(relation)
Definition: rel.h:440
static void addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok, LOCKMODE lockmode)
Definition: tablecmds.c:8188
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
bool can_coerce_type(int nargs, const Oid *input_typeids, const Oid *target_typeids, CoercionContext ccontext)
Definition: parse_coerce.c:543
#define FKCONSTR_ACTION_SETDEFAULT
Definition: parsenodes.h:2119
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids)
Definition: tablecmds.c:9245
bool rd_islocaltemp
Definition: rel.h:60
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:570
#define MemSet(start, val, len)
Definition: c.h:941
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
List * pk_attrs
Definition: parsenodes.h:2165
char * conname
Definition: parsenodes.h:2132
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:9557
#define OidIsValid(objectId)
Definition: c.h:638
CoercionPathType
Definition: parse_coerce.h:24
static ObjectAddress addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel, Relation pkrel, Oid indexOid, Oid parentConstr, int numfks, int16 *pkattnum, int16 *fkattnum, Oid *pfeqoperators, Oid *ppeqoperators, Oid *ffeqoperators, bool old_check_ok)
Definition: tablecmds.c:7982
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
TupleDesc oldDesc
Definition: tablecmds.c:158
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:860
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
#define RelationGetRelationName(relation)
Definition: rel.h:448
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define lnext(lc)
Definition: pg_list.h:105
#define ereport(elevel, rest)
Definition: elog.h:141
Oid old_pktable_oid
Definition: parsenodes.h:2170
#define FKCONSTR_ACTION_CASCADE
Definition: parsenodes.h:2117
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:68
bool allowSystemTableMods
Definition: globals.c:120
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2175
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
Definition: tablecmds.c:9290
char fk_del_action
Definition: parsenodes.h:2168
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:9528
#define INDEX_MAX_KEYS
static int list_length(const List *l)
Definition: pg_list.h:89
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
Definition: tablecmds.c:9387
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
int i
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
RangeVar * pktable
Definition: parsenodes.h:2163
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2299
#define FKCONSTR_ACTION_SETNULL
Definition: parsenodes.h:2118
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
bool skip_validation
Definition: parsenodes.h:2174
#define RelationGetRelid(relation)
Definition: rel.h:414
List * fk_attrs
Definition: parsenodes.h:2164
#define BTEqualStrategyNumber
Definition: stratnum.h:31
char fk_upd_action
Definition: parsenodes.h:2167
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ ATColumnChangeRequiresRewrite()

static bool ATColumnChangeRequiresRewrite ( Node expr,
AttrNumber  varattno 
)
static

Definition at line 10442 of file tablecmds.c.

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

Referenced by ATPrepAlterColumnType().

10443 {
10444  Assert(expr != NULL);
10445 
10446  for (;;)
10447  {
10448  /* only one varno, so no need to check that */
10449  if (IsA(expr, Var) &&((Var *) expr)->varattno == varattno)
10450  return false;
10451  else if (IsA(expr, RelabelType))
10452  expr = (Node *) ((RelabelType *) expr)->arg;
10453  else if (IsA(expr, CoerceToDomain))
10454  {
10455  CoerceToDomain *d = (CoerceToDomain *) expr;
10456 
10458  return true;
10459  expr = (Node *) d->arg;
10460  }
10461  else if (IsA(expr, FuncExpr))
10462  {
10463  FuncExpr *f = (FuncExpr *) expr;
10464 
10465  switch (f->funcid)
10466  {
10467  case F_TIMESTAMPTZ_TIMESTAMP:
10468  case F_TIMESTAMP_TIMESTAMPTZ:
10470  return true;
10471  else
10472  expr = linitial(f->args);
10473  break;
10474  default:
10475  return true;
10476  }
10477  }
10478  else
10479  return true;
10480  }
10481 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:575
List * args
Definition: primnodes.h:463
Definition: nodes.h:524
Definition: primnodes.h:167
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1289
#define linitial(l)
Definition: pg_list.h:111
Oid funcid
Definition: primnodes.h:455
#define Assert(condition)
Definition: c.h:732
void * arg
bool TimestampTimestampTzRequiresRewrite(void)
Definition: timestamp.c:5178

◆ ATController()

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

Definition at line 3810 of file tablecmds.c.

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

Referenced by AlterTable(), and AlterTableInternal().

3812 {
3813  List *wqueue = NIL;
3814  ListCell *lcmd;
3815 
3816  /* Phase 1: preliminary examination of commands, create work queue */
3817  foreach(lcmd, cmds)
3818  {
3819  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3820 
3821  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode);
3822  }
3823 
3824  /* Close the relation, but keep lock until commit */
3825  relation_close(rel, NoLock);
3826 
3827  /* Phase 2: update system catalogs */
3828  ATRewriteCatalogs(&wqueue, lockmode);
3829 
3830  /* Phase 3: scan/rewrite tables as needed */
3831  ATRewriteTables(parsetree, &wqueue, lockmode);
3832 }
#define NIL
Definition: pg_list.h:69
#define NoLock
Definition: lockdefs.h:34
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
Definition: tablecmds.c:4480
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:3844
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define lfirst(lc)
Definition: pg_list.h:106
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode)
Definition: tablecmds.c:4135
Definition: pg_list.h:45

◆ ATDetachCheckNoForeignKeyRefs()

static void ATDetachCheckNoForeignKeyRefs ( Relation  partition)
static

Definition at line 16522 of file tablecmds.c.

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

Referenced by ATExecDetachPartition().

16523 {
16524  List *constraints;
16525  ListCell *cell;
16526 
16527  constraints = GetParentedForeignKeyRefs(partition);
16528 
16529  foreach(cell, constraints)
16530  {
16531  Oid constrOid = lfirst_oid(cell);
16532  HeapTuple tuple;
16533  Form_pg_constraint constrForm;
16534  Relation rel;
16535  Trigger trig;
16536 
16537  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
16538  if (!HeapTupleIsValid(tuple))
16539  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
16540  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
16541 
16542  Assert(OidIsValid(constrForm->conparentid));
16543  Assert(constrForm->confrelid == RelationGetRelid(partition));
16544 
16545  /* prevent data changes into the referencing table until commit */
16546  rel = table_open(constrForm->conrelid, ShareLock);
16547 
16548  MemSet(&trig, 0, sizeof(trig));
16549  trig.tgoid = InvalidOid;
16550  trig.tgname = NameStr(constrForm->conname);
16552  trig.tgisinternal = true;
16553  trig.tgconstrrelid = RelationGetRelid(partition);
16554  trig.tgconstrindid = constrForm->conindid;
16555  trig.tgconstraint = constrForm->oid;
16556  trig.tgdeferrable = false;
16557  trig.tginitdeferred = false;
16558  /* we needn't fill in remaining fields */
16559 
16560  RI_PartitionRemove_Check(&trig, rel, partition);
16561 
16562  ReleaseSysCache(tuple);
16563 
16564  table_close(rel, NoLock);
16565  }
16566 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static List * GetParentedForeignKeyRefs(Relation partition)
Definition: tablecmds.c:16469
Oid tgoid
Definition: reltrigger.h:25
bool tgisinternal
Definition: reltrigger.h:31
#define MemSet(start, val, len)
Definition: c.h:941
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:638
#define TRIGGER_FIRES_ON_ORIGIN
Definition: trigger.h:155
char tgenabled
Definition: reltrigger.h:30
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Oid tgconstraint
Definition: reltrigger.h:34
char * tgname
Definition: reltrigger.h:27
void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1572
bool tgdeferrable
Definition: reltrigger.h:35
bool tginitdeferred
Definition: reltrigger.h:36
#define NoLock
Definition: lockdefs.h:34
Oid tgconstrrelid
Definition: reltrigger.h:32
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
#define InvalidOid
Definition: postgres_ext.h:36
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
Oid tgconstrindid
Definition: reltrigger.h:33
#define elog(elevel,...)
Definition: elog.h:226
#define ShareLock
Definition: lockdefs.h:41
#define NameStr(name)
Definition: c.h:609
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:414
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ AtEOSubXact_on_commit_actions()

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

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

14630 {
14631  ListCell *cur_item;
14632  ListCell *prev_item;
14633 
14634  prev_item = NULL;
14635  cur_item = list_head(on_commits);
14636 
14637  while (cur_item != NULL)
14638  {
14639  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
14640 
14641  if (!isCommit && oc->creating_subid == mySubid)
14642  {
14643  /* cur_item must be removed */
14644  on_commits = list_delete_cell(on_commits, cur_item, prev_item);
14645  pfree(oc);
14646  if (prev_item)
14647  cur_item = lnext(prev_item);
14648  else
14649  cur_item = list_head(on_commits);
14650  }
14651  else
14652  {
14653  /* cur_item must be preserved */
14654  if (oc->creating_subid == mySubid)
14655  oc->creating_subid = parentSubid;
14656  if (oc->deleting_subid == mySubid)
14657  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
14658  prev_item = cur_item;
14659  cur_item = lnext(prev_item);
14660  }
14661  }
14662 }
SubTransactionId creating_subid
Definition: tablecmds.c:119
void pfree(void *pointer)
Definition: mcxt.c:1031
static List * on_commits
Definition: tablecmds.c:123
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:120
#define lfirst(lc)
Definition: pg_list.h:106
#define InvalidSubTransactionId
Definition: c.h:513

◆ AtEOXact_on_commit_actions()

void AtEOXact_on_commit_actions ( bool  isCommit)

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

14587 {
14588  ListCell *cur_item;
14589  ListCell *prev_item;
14590 
14591  prev_item = NULL;
14592  cur_item = list_head(on_commits);
14593 
14594  while (cur_item != NULL)
14595  {
14596  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
14597 
14598  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
14600  {
14601  /* cur_item must be removed */
14602  on_commits = list_delete_cell(on_commits, cur_item, prev_item);
14603  pfree(oc);
14604  if (prev_item)
14605  cur_item = lnext(prev_item);
14606  else
14607  cur_item = list_head(on_commits);
14608  }
14609  else
14610  {
14611  /* cur_item must be preserved */
14614  prev_item = cur_item;
14615  cur_item = lnext(prev_item);
14616  }
14617  }
14618 }
SubTransactionId creating_subid
Definition: tablecmds.c:119
void pfree(void *pointer)
Definition: mcxt.c:1031
static List * on_commits
Definition: tablecmds.c:123
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:120
#define lfirst(lc)
Definition: pg_list.h:106
#define InvalidSubTransactionId
Definition: c.h:513

◆ ATExecAddColumn()

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

Definition at line 5529 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_DEFAULT_VAL, ATGetQueueEntry(), ATSimplePermissions(), ATT_FOREIGN_TABLE, ATT_TABLE, RawColumnDefault::attnum, NewColumnValue::attnum, 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, RawColumnDefault::generated, ColumnDef::generated, get_collation_name(), get_typcollation(), getBaseTypeAndTypmod(), GetColumnDefCollation(), GETSTRUCT, GetUserId(), heap_freetuple(), HeapTupleIsValid, ColumnDef::identity, ColumnDef::identitySequence, ColumnDef::inhcount, InsertPgAttributeTuple(), InvalidObjectAddress, InvokeObjectPostCreateHook, ColumnDef::is_local, ColumnDef::is_not_null, lappend(), lfirst_oid, list_length(), list_make1, list_make1_oid, makeNode, makeNullConst(), MaxHeapAttributeNumber, RawColumnDefault::missingMode, namestrcpy(), newval, AlteredTableInfo::newvals, NIL, NoLock, NOTICE, ObjectAddressSubSet, ObjectIdGetDatum, palloc(), palloc0(), pg_type_aclcheck(), RangeVarGetRelid, RawColumnDefault::raw_default, ColumnDef::raw_default, RelationData::rd_att, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), relkind, relnatts, RELOID, AlteredTableInfo::rewrite, RowExclusiveLock, SearchSysCacheCopy1, SearchSysCacheCopyAttName(), NextValueExpr::seqid, HeapTupleData::t_self, table_close(), table_open(), TupleDescAttr, NextValueExpr::typeId, ColumnDef::typeName, typenameType(), typenameTypeIdAndMod(), and AlteredTableInfo::verify_new_notnull.

Referenced by ATExecCmd().

5533 {
5534  Oid myrelid = RelationGetRelid(rel);
5535  Relation pgclass,
5536  attrdesc;
5537  HeapTuple reltup;
5538  FormData_pg_attribute attribute;
5539  int newattnum;
5540  char relkind;
5541  HeapTuple typeTuple;
5542  Oid typeOid;
5543  int32 typmod;
5544  Oid collOid;
5545  Form_pg_type tform;
5546  Expr *defval;
5547  List *children;
5548  ListCell *child;
5549  AclResult aclresult;
5550  ObjectAddress address;
5551 
5552  /* At top level, permission check was done in ATPrepCmd, else do it */
5553  if (recursing)
5555 
5556  if (rel->rd_rel->relispartition && !recursing)
5557  ereport(ERROR,
5558  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5559  errmsg("cannot add column to a partition")));
5560 
5561  attrdesc = table_open(AttributeRelationId, RowExclusiveLock);
5562 
5563  /*
5564  * Are we adding the column to a recursion child? If so, check whether to
5565  * merge with an existing definition for the column. If we do merge, we
5566  * must not recurse. Children will already have the column, and recursing
5567  * into them would mess up attinhcount.
5568  */
5569  if (colDef->inhcount > 0)
5570  {
5571  HeapTuple tuple;
5572 
5573  /* Does child already have a column by this name? */
5574  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
5575  if (HeapTupleIsValid(tuple))
5576  {
5577  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
5578  Oid ctypeId;
5579  int32 ctypmod;
5580  Oid ccollid;
5581 
5582  /* Child column must match on type, typmod, and collation */
5583  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
5584  if (ctypeId != childatt->atttypid ||
5585  ctypmod != childatt->atttypmod)
5586  ereport(ERROR,
5587  (errcode(ERRCODE_DATATYPE_MISMATCH),
5588  errmsg("child table \"%s\" has different type for column \"%s\"",
5589  RelationGetRelationName(rel), colDef->colname)));
5590  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
5591  if (ccollid != childatt->attcollation)
5592  ereport(ERROR,
5593  (errcode(ERRCODE_COLLATION_MISMATCH),
5594  errmsg("child table \"%s\" has different collation for column \"%s\"",
5595  RelationGetRelationName(rel), colDef->colname),
5596  errdetail("\"%s\" versus \"%s\"",
5597  get_collation_name(ccollid),
5598  get_collation_name(childatt->attcollation))));
5599 
5600  /* Bump the existing child att's inhcount */
5601  childatt->attinhcount++;
5602  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
5603 
5604  heap_freetuple(tuple);
5605 
5606  /* Inform the user about the merge */
5607  ereport(NOTICE,
5608  (errmsg("merging definition of column \"%s\" for child \"%s\"",
5609  colDef->colname, RelationGetRelationName(rel))));
5610 
5611  table_close(attrdesc, RowExclusiveLock);
5612  return InvalidObjectAddress;
5613  }
5614  }
5615 
5616  pgclass = table_open(RelationRelationId, RowExclusiveLock);
5617 
5618  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
5619  if (!HeapTupleIsValid(reltup))
5620  elog(ERROR, "cache lookup failed for relation %u", myrelid);
5621  relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
5622 
5623  /*
5624  * Cannot add identity column if table has children, because identity does
5625  * not inherit. (Adding column and identity separately will work.)
5626  */
5627  if (colDef->identity &&
5628  recurse &&
5629  find_inheritance_children(myrelid, NoLock) != NIL)
5630  ereport(ERROR,
5631  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
5632  errmsg("cannot recursively add identity column to table that has child tables")));
5633 
5634  /* skip if the name already exists and if_not_exists is true */
5635  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
5636  {
5637  table_close(attrdesc, RowExclusiveLock);
5638  heap_freetuple(reltup);
5639  table_close(pgclass, RowExclusiveLock);
5640  return InvalidObjectAddress;
5641  }
5642 
5643  /* Determine the new attribute's number */
5644  newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
5645  if (newattnum > MaxHeapAttributeNumber)
5646  ereport(ERROR,
5647  (errcode(ERRCODE_TOO_MANY_COLUMNS),
5648  errmsg("tables can have at most %d columns",
5650 
5651  typeTuple = typenameType(NULL, colDef->typeName, &typmod);
5652  tform = (Form_pg_type) GETSTRUCT(typeTuple);
5653  typeOid = tform->oid;
5654 
5655  aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
5656  if (aclresult != ACLCHECK_OK)
5657  aclcheck_error_type(aclresult, typeOid);
5658 
5659  collOid = GetColumnDefCollation(NULL, colDef, typeOid);
5660 
5661  /* make sure datatype is legal for a column */
5662  CheckAttributeType(colDef->colname, typeOid, collOid,
5663  list_make1_oid(rel->rd_rel->reltype),
5664  0);
5665 
5666  /* construct new attribute's pg_attribute entry */
5667  attribute.attrelid = myrelid;
5668  namestrcpy(&(attribute.attname), colDef->colname);
5669  attribute.atttypid = typeOid;
5670  attribute.attstattarget = (newattnum > 0) ? -1 : 0;
5671  attribute.attlen = tform->typlen;
5672  attribute.atttypmod = typmod;
5673  attribute.attnum = newattnum;
5674  attribute.attbyval = tform->typbyval;
5675  attribute.attndims = list_length(colDef->typeName->arrayBounds);
5676  attribute.attstorage = tform->typstorage;
5677  attribute.attalign = tform->typalign;
5678  attribute.attnotnull = colDef->is_not_null;
5679  attribute.atthasdef = false;
5680  attribute.atthasmissing = false;
5681  attribute.attidentity = colDef->identity;
5682  attribute.attgenerated = colDef->generated;
5683  attribute.attisdropped = false;
5684  attribute.attislocal = colDef->is_local;
5685  attribute.attinhcount = colDef->inhcount;
5686  attribute.attcollation = collOid;
5687  /* attribute.attacl is handled by InsertPgAttributeTuple */
5688 
5689  ReleaseSysCache(typeTuple);
5690 
5691  InsertPgAttributeTuple(attrdesc, &attribute, NULL);
5692 
5693  table_close(attrdesc, RowExclusiveLock);
5694 
5695  /*
5696  * Update pg_class tuple as appropriate
5697  */
5698  ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
5699 
5700  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
5701 
5702  heap_freetuple(reltup);
5703 
5704  /* Post creation hook for new attribute */
5705  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
5706 
5707  table_close(pgclass, RowExclusiveLock);
5708 
5709  /* Make the attribute's catalog entry visible */
5711 
5712  /*
5713  * Store the DEFAULT, if any, in the catalogs
5714  */
5715  if (colDef->raw_default)
5716  {
5717  RawColumnDefault *rawEnt;
5718 
5719  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
5720  rawEnt->attnum = attribute.attnum;
5721  rawEnt->raw_default = copyObject(colDef->raw_default);
5722 
5723  /*
5724  * Attempt to skip a complete table rewrite by storing the specified
5725  * DEFAULT value outside of the heap. This may be disabled inside
5726  * AddRelationNewConstraints if the optimization cannot be applied.
5727  */
5728  rawEnt->missingMode = (!colDef->generated);
5729 
5730  rawEnt->generated = colDef->generated;
5731 
5732  /*
5733  * This function is intended for CREATE TABLE, so it processes a
5734  * _list_ of defaults, but we just do one.
5735  */
5737  false, true, false, NULL);
5738 
5739  /* Make the additional catalog changes visible */
5741 
5742  /*
5743  * Did the request for a missing value work? If not we'll have to do a
5744  * rewrite
5745  */
5746  if (!rawEnt->missingMode)
5748  }
5749 
5750  /*
5751  * Tell Phase 3 to fill in the default expression, if there is one.
5752  *
5753  * If there is no default, Phase 3 doesn't have to do anything, because
5754  * that effectively means that the default is NULL. The heap tuple access
5755  * routines always check for attnum > # of attributes in tuple, and return
5756  * NULL if so, so without any modification of the tuple data we will get
5757  * the effect of NULL values in the new column.
5758  *
5759  * An exception occurs when the new column is of a domain type: the domain
5760  * might have a NOT NULL constraint, or a check constraint that indirectly
5761  * rejects nulls. If there are any domain constraints then we construct
5762  * an explicit NULL default value that will be passed through
5763  * CoerceToDomain processing. (This is a tad inefficient, since it causes
5764  * rewriting the table which we really don't have to do, but the present
5765  * design of domain processing doesn't offer any simple way of checking
5766  * the constraints more directly.)
5767  *
5768  * Note: we use build_column_default, and not just the cooked default
5769  * returned by AddRelationNewConstraints, so that the right thing happens
5770  * when a datatype's default applies.
5771  *
5772  * We skip this step completely for views and foreign tables. For a view,
5773  * we can only get here from CREATE OR REPLACE VIEW, which historically
5774  * doesn't set up defaults, not even for domain-typed columns. And in any
5775  * case we mustn't invoke Phase 3 on a view or foreign table, since they
5776  * have no storage.
5777  */
5778  if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE
5779  && relkind != RELKIND_FOREIGN_TABLE && attribute.attnum > 0)
5780  {
5781  /*
5782  * For an identity column, we can't use build_column_default(),
5783  * because the sequence ownership isn't set yet. So do it manually.
5784  */
5785  if (colDef->identity)
5786  {
5788 
5789  nve->seqid = RangeVarGetRelid(colDef->identitySequence, NoLock, false);
5790  nve->typeId = typeOid;
5791 
5792  defval = (Expr *) nve;
5793 
5794  /* must do a rewrite for identity columns */
5796  }
5797  else
5798  defval = (Expr *) build_column_default(rel, attribute.attnum);
5799 
5800  if (!defval && DomainHasConstraints(typeOid))
5801  {
5802  Oid baseTypeId;
5803  int32 baseTypeMod;
5804  Oid baseTypeColl;
5805 
5806  baseTypeMod = typmod;
5807  baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
5808  baseTypeColl = get_typcollation(baseTypeId);
5809  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
5810  defval = (Expr *) coerce_to_target_type(NULL,
5811  (Node *) defval,
5812  baseTypeId,
5813  typeOid,
5814  typmod,
5817  -1);
5818  if (defval == NULL) /* should not happen */
5819  elog(ERROR, "failed to coerce base type to domain");
5820  }
5821 
5822  if (defval)
5823  {
5825 
5826  newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
5827  newval->attnum = attribute.attnum;
5828  newval->expr = expression_planner(defval);
5829 
5830  tab->newvals = lappend(tab->newvals, newval);
5831  }
5832 
5833  if (DomainHasConstraints(typeOid))
5835 
5836  if (!TupleDescAttr(rel->rd_att, attribute.attnum - 1)->atthasmissing)
5837  {
5838  /*
5839  * If the new column is NOT NULL, and there is no missing value,
5840  * tell Phase 3 it needs to check for NULLs.
5841  */
5842  tab->verify_new_notnull |= colDef->is_not_null;
5843  }
5844  }
5845 
5846  /*
5847  * Add needed dependency entries for the new column.
5848  */
5849  add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
5850  add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
5851 
5852  /*
5853  * Propagate to children as appropriate. Unlike most other ALTER
5854  * routines, we have to do this one level of recursion at a time; we can't
5855  * use find_all_inheritors to do it in one pass.
5856  */
5857  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
5858 
5859  /*
5860  * If we are told not to recurse, there had better not be any child
5861  * tables; else the addition would put them out of step.
5862  */
5863  if (children && !recurse)
5864  ereport(ERROR,
5865  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
5866  errmsg("column must be added to child tables too")));
5867 
5868  /* Children should see column as singly inherited */
5869  if (!recursing)
5870  {
5871  colDef = copyObject(colDef);
5872  colDef->inhcount = 1;
5873  colDef->is_local = false;
5874  }
5875 
5876  foreach(child, children)
5877  {
5878  Oid childrelid = lfirst_oid(child);
5879  Relation childrel;
5880  AlteredTableInfo *childtab;
5881 
5882  /* find_inheritance_children already got lock */
5883  childrel = table_open(childrelid, NoLock);
5884  CheckTableNotInUse(childrel, "ALTER TABLE");
5885 
5886  /* Find or create work queue entry for this table */
5887  childtab = ATGetQueueEntry(wqueue, childrel);
5888 
5889  /* Recurse to child; return value is ignored */
5890  ATExecAddColumn(wqueue, childtab, childrel,
5891  colDef, recurse, true,
5892  if_not_exists, lockmode);
5893 
5894  table_close(childrel, NoLock);
5895  }
5896 
5897  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
5898  return address;
5899 }
#define NIL
Definition: pg_list.h:69
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal, const char *queryString)
Definition: heap.c:2492
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2316
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
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:28
bool is_local
Definition: parsenodes.h:649
Oid GetUserId(void)
Definition: miscinit.c:380
char identity
Definition: parsenodes.h:655
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:63
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
char * get_collation_name(Oid colloid)
Definition: lsyscache.c:923
Expr * expression_planner(Expr *expr)
Definition: planner.c:6040
Definition: nodes.h:524
int errcode(int sqlerrcode)
Definition: elog.c:570
char generated
Definition: parsenodes.h:658
bool is_not_null
Definition: parsenodes.h:650
Form_pg_class rd_rel
Definition: rel.h:84
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define ATT_TABLE
Definition: tablecmds.c:286
int namestrcpy(Name name, const char *str)
Definition: name.c:250
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3666
char relkind
Definition: pg_class.h:81
signed int int32
Definition: c.h:346
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:336
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1289
#define list_make1(x1)
Definition: pg_list.h:139
RangeVar * identitySequence
Definition: parsenodes.h:656
#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:5959
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:1288
ItemPointerData t_self
Definition: htup.h:65
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:5977
bool missingMode
Definition: heap.h:30
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:860
char generated
Definition: heap.h:31
#define RelationGetRelationName(relation)
Definition: rel.h:448
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:5052
Node * raw_default
Definition: heap.h:29
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define ACL_USAGE
Definition: parsenodes.h:82
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:3399
#define ereport(elevel, rest)
Definition: elog.h:141
bool verify_new_notnull
Definition: tablecmds.c:164
Node * raw_default
Definition: parsenodes.h:653
List * lappend(List *list, void *datum)
Definition: list.c:128
int16 relnatts
Definition: pg_class.h:84
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:955
AclResult
Definition: acl.h:178
void CommandCounterIncrement(void)
Definition: xact.c:1003
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
#define list_make1_oid(x1)
Definition: pg_list.h:151
TupleDesc rd_att
Definition: rel.h:85
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:184
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:55
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:2823
#define NOTICE
Definition: elog.h:37
#define MaxHeapAttributeNumber
Definition: htup_details.h:47
#define makeNode(_type_)
Definition: nodes.h:572
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
FormData_pg_type * Form_pg_type
Definition: pg_type.h:251
static int list_length(const List *l)
Definition: pg_list.h:89
#define newval
TypeName * typeName
Definition: parsenodes.h:647
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
FormData_pg_class * Form_pg_class
Definition: pg_class.h:150
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
List * arrayBounds
Definition: parsenodes.h:215
void InsertPgAttributeTuple(Relation pg_attribute_rel, Form_pg_attribute new_attribute, CatalogIndexState indstate)
Definition: heap.c:695
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:784
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:5906
#define elog(elevel,...)
Definition: elog.h:226
int inhcount
Definition: parsenodes.h:648
static void ATSimplePermissions(Relation rel, int allowed_targets)
Definition: tablecmds.c:5089
char * colname
Definition: parsenodes.h:646
#define copyObject(obj)
Definition: nodes.h:640
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, int flags)
Definition: heap.c:579
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4743
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:45
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:291
#define RelationGetRelid(relation)
Definition: rel.h:414
#define lfirst_oid(lc)
Definition: pg_list.h:108
static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, ColumnDef *colDef, bool recurse, bool recursing, bool if_not_exists, LOCKMODE lockmode)
Definition: tablecmds.c:5529
AttrNumber attnum
Definition: tablecmds.c:201

◆ ATExecAddConstraint()

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

Definition at line 7292 of file tablecmds.c.

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

Referenced by ATExecCmd().

7295 {
7297 
7298  Assert(IsA(newConstraint, Constraint));
7299 
7300  /*
7301  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
7302  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
7303  * switch anyway to make it easier to add more code later.
7304  */
7305  switch (newConstraint->contype)
7306  {
7307  case CONSTR_CHECK:
7308  address =
7309  ATAddCheckConstraint(wqueue, tab, rel,
7310  newConstraint, recurse, false, is_readd,
7311  lockmode);
7312  break;
7313 
7314  case CONSTR_FOREIGN:
7315 
7316  /*
7317  * Assign or validate constraint name
7318  */
7319  if (newConstraint->conname)
7320  {
7322  RelationGetRelid(rel),
7323  newConstraint->conname))
7324  ereport(ERROR,
7326  errmsg("constraint \"%s\" for relation \"%s\" already exists",
7327  newConstraint->conname,
7328  RelationGetRelationName(rel))));
7329  }
7330  else
7331  newConstraint->conname =
7334  "fkey",
7335  RelationGetNamespace(rel),
7336  NIL);
7337 
7338  address = ATAddForeignKeyConstraint(wqueue, tab, rel,
7339  newConstraint, InvalidOid,
7340  recurse, false,
7341  lockmode);
7342  break;
7343 
7344  default:
7345  elog(ERROR, "unrecognized constraint type: %d",
7346  (int) newConstraint->contype);
7347  }
7348 
7349  return address;
7350 }
#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:575
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
static char * ChooseForeignKeyConstraintNameAddition(List *colnames)
Definition: tablecmds.c:7365
int errcode(int sqlerrcode)
Definition: elog.c:570
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:7407
char * conname
Definition: parsenodes.h:2132
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:448
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:732
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
static ObjectAddress ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, Oid parentConstr, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:7543
ConstrType contype
Definition: parsenodes.h:2129
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:33
#define RelationGetRelid(relation)
Definition: rel.h:414
List * fk_attrs
Definition: parsenodes.h:2164
#define RelationGetNamespace(relation)
Definition: rel.h:455

◆ ATExecAddIdentity()

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

Definition at line 6410 of file tablecmds.c.

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

Referenced by ATExecCmd().

6412 {
6413  Relation attrelation;
6414  HeapTuple tuple;
6415  Form_pg_attribute attTup;
6417  ObjectAddress address;
6418  ColumnDef *cdef = castNode(ColumnDef, def);
6419 
6420  attrelation = table_open(AttributeRelationId, RowExclusiveLock);
6421 
6422  tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
6423  if (!HeapTupleIsValid(tuple))
6424  ereport(ERROR,
6425  (errcode(ERRCODE_UNDEFINED_COLUMN),
6426  errmsg("column \"%s\" of relation \"%s\" does not exist",
6427  colName, RelationGetRelationName(rel))));
6428  attTup = (Form_pg_attribute) GETSTRUCT(tuple);
6429  attnum = attTup->attnum;
6430 
6431  /* Can't alter a system attribute */
6432  if (attnum <= 0)
6433  ereport(ERROR,
6434  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6435  errmsg("cannot alter system column \"%s\"",
6436  colName)));
6437 
6438  /*
6439  * Creating a column as identity implies NOT NULL, so adding the identity
6440  * to an existing column that is not NOT NULL would create a state that
6441  * cannot be reproduced without contortions.
6442  */
6443  if (!attTup->attnotnull)
6444  ereport(ERROR,
6445  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
6446  errmsg("column \"%s\" of relation \"%s\" must be declared NOT NULL before identity can be added",
6447  colName, RelationGetRelationName(rel))));
6448 
6449  if (attTup->attidentity)
6450  ereport(ERROR,
6451  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
6452  errmsg("column \"%s\" of relation \"%s\" is already an identity column",
6453  colName, RelationGetRelationName(rel))));
6454 
6455  if (attTup->atthasdef)
6456  ereport(ERROR,
6457  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
6458  errmsg("column \"%s\" of relation \"%s\" already has a default value",
6459  colName, RelationGetRelationName(rel))));
6460 
6461  attTup->attidentity = cdef->identity;
6462  CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
6463 
6464  InvokeObjectPostAlterHook(RelationRelationId,
6465  RelationGetRelid(rel),
6466  attTup->attnum);
6467  ObjectAddressSubSet(address, RelationRelationId,
6468  RelationGetRelid(rel), attnum);
6469  heap_freetuple(tuple);
6470 
6471  table_close(attrelation, RowExclusiveLock);
6472 
6473  return address;
6474 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define castNode(_type_, nodeptr)
Definition: nodes.h:593
char identity
Definition: parsenodes.h:655
int errcode(int sqlerrcode)
Definition: elog.c:570
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:1288
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:448
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
int16 attnum
Definition: pg_attribute.h:79
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
int errmsg(const char *fmt,...)
Definition: elog.c:784
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:414

◆ ATExecAddIndex()

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

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

7147 {
7148  bool check_rights;
7149  bool skip_build;
7150  bool quiet;
7151  ObjectAddress address;
7152 
7153  Assert(IsA(stmt, IndexStmt));
7154  Assert(!stmt->concurrent);
7155 
7156  /* The IndexStmt has already been through transformIndexStmt */
7157  Assert(stmt->transformed);
7158 
7159  /* suppress schema rights check when rebuilding existing index */
7160  check_rights = !is_rebuild;
7161  /* skip index build if phase 3 will do it or we're reusing an old one */
7162  skip_build = tab->rewrite > 0 || OidIsValid(stmt->oldNode);
7163  /* suppress notices when rebuilding existing index */
7164  quiet = is_rebuild;
7165 
7166  address = DefineIndex(RelationGetRelid(rel),
7167  stmt,
7168  InvalidOid, /* no predefined OID */
7169  InvalidOid, /* no parent index */
7170  InvalidOid, /* no parent constraint */
7171  true, /* is_alter_table */
7172  check_rights,
7173  false, /* check_not_in_use - we did it already */
7174  skip_build,
7175  quiet);
7176 
7177  /*
7178  * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
7179  * index instead of building from scratch. The DROP of the old edition of
7180  * this index will have scheduled the storage for deletion at commit, so
7181  * cancel that pending deletion.
7182  */
7183  if (OidIsValid(stmt->oldNode))
7184  {
7185  Relation irel = index_open(address.objectId, NoLock);
7186 
7187  RelationPreserveStorage(irel->rd_node, true);
7188  index_close(irel, NoLock);
7189  }
7190 
7191  return address;
7192 }
void RelationPreserveStorage(RelFileNode rnode, bool atCommit)
Definition: storage.c:193
#define IsA(nodeptr, _type_)
Definition: nodes.h:575
ObjectAddress DefineIndex(Oid relationId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition: indexcmds.c:438
#define OidIsValid(objectId)
Definition: c.h:638
#define NoLock
Definition: lockdefs.h:34
bool transformed
Definition: parsenodes.h:2770
#define InvalidOid
Definition: postgres_ext.h:36
RelFileNode rd_node
Definition: rel.h:55
#define Assert(condition)
Definition: c.h:732
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:152
bool concurrent
Definition: parsenodes.h:2771
#define RelationGetRelid(relation)
Definition: rel.h:414
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:126

◆ ATExecAddIndexConstraint()

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

Definition at line 7200 of file tablecmds.c.

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

Referenced by ATExecCmd().

7202 {
7203  Oid index_oid = stmt->indexOid;
7204  Relation indexRel;
7205  char *indexName;
7206  IndexInfo *indexInfo;
7207  char *constraintName;
7208  char constraintType;
7209  ObjectAddress address;
7210  bits16 flags;
7211 
7212  Assert(IsA(stmt, IndexStmt));
7213  Assert(OidIsValid(index_oid));
7214  Assert(stmt->isconstraint);
7215 
7216  /*
7217  * Doing this on partitioned tables is not a simple feature to implement,
7218  * so let's punt for now.
7219  */
7220  if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
7221  ereport(ERROR,
7222  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7223  errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
7224 
7225  indexRel = index_open(index_oid, AccessShareLock);
7226 
7227  indexName = pstrdup(RelationGetRelationName(indexRel));
7228 
7229  indexInfo = BuildIndexInfo(indexRel);
7230 
7231  /* this should have been checked at parse time */
7232  if (!indexInfo->ii_Unique)
7233  elog(ERROR, "index \"%s\" is not unique", indexName);
7234 
7235  /*
7236  * Determine name to assign to constraint. We require a constraint to
7237  * have the same name as the underlying index; therefore, use the index's
7238  * existing name as the default constraint name, and if the user
7239  * explicitly gives some other name for the constraint, rename the index
7240  * to match.
7241  */
7242  constraintName = stmt->idxname;
7243  if (constraintName == NULL)
7244  constraintName = indexName;
7245  else if (strcmp(constraintName, indexName) != 0)
7246  {
7247  ereport(NOTICE,
7248  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
7249  indexName, constraintName)));
7250  RenameRelationInternal(index_oid, constraintName, false, true);
7251  }
7252 
7253  /* Extra checks needed if making primary key */
7254  if (stmt->primary)
7255  index_check_primary_key(rel, indexInfo, true, stmt);
7256 
7257  /* Note we currently don't support EXCLUSION constraints here */
7258  if (stmt->primary)
7259  constraintType = CONSTRAINT_PRIMARY;
7260  else
7261  constraintType = CONSTRAINT_UNIQUE;
7262 
7263  /* Create the catalog entries for the constraint */
7269 
7270  address = index_constraint_create(rel,
7271  index_oid,
7272  InvalidOid,
7273  indexInfo,
7274  constraintName,
7275  constraintType,
7276  flags,
7278  false); /* is_internal */
7279 
7280  index_close(indexRel, NoLock);
7281 
7282  return address;
7283 }
bool deferrable
Definition: parsenodes.h:2768
bool primary
Definition: parsenodes.h:2766
#define IsA(nodeptr, _type_)
Definition: nodes.h:575
uint16 bits16
Definition: c.h:366
char * pstrdup(const char *in)
Definition: mcxt.c:1161
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:570
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2168
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS
Definition: index.h:79
void index_check_primary_key(Relation heapRel, IndexInfo *indexInfo, bool is_alter_table, IndexStmt *stmt)
Definition: index.c:201
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:638
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:77
Oid indexOid
Definition: parsenodes.h:2763
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:448
#define ereport(elevel, rest)
Definition: elog.h:141
char * idxname
Definition: parsenodes.h:2752
bool allowSystemTableMods
Definition: globals.c:120
#define InvalidOid
Definition: postgres_ext.h:36
#define NOTICE
Definition: elog.h:37
bool ii_Unique
Definition: execnodes.h:169
#define Assert(condition)
Definition: c.h:732
bool initdeferred
Definition: parsenodes.h:2769
#define INDEX_CONSTR_CREATE_UPDATE_INDEX
Definition: index.h:78
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:152
bool isconstraint
Definition: parsenodes.h:2767
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3297
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:76
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:126
#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY
Definition: index.h:75
ObjectAddress index_constraint_create(Relation heapRelation, Oid indexRelationId, Oid parentConstraintId, IndexInfo *indexInfo, const char *constraintName, char constraintType, bits16 constr_flags, bool allow_system_table_mods, bool is_internal)
Definition: index.c:1675

◆ ATExecAddInherit()

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

Definition at line 12697 of file tablecmds.c.

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

Referenced by ATExecCmd().

12698 {
12699  Relation parent_rel;
12700  List *children;
12701  ObjectAddress address;
12702  const char *trigger_name;
12703 
12704  /*
12705  * A self-exclusive lock is needed here. See the similar case in
12706  * MergeAttributes() for a full explanation.
12707  */
12708  parent_rel = table_openrv(parent, ShareUpdateExclusiveLock);
12709 
12710  /*
12711  * Must be owner of both parent and child -- child was checked by
12712  * ATSimplePermissions call in ATPrepCmd
12713  */
12715 
12716  /* Permanent rels cannot inherit from temporary ones */
12717  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
12718  child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
12719  ereport(ERROR,
12720  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12721  errmsg("cannot inherit from temporary relation \"%s\"",
12722  RelationGetRelationName(parent_rel))));
12723 
12724  /* If parent rel is temp, it must belong to this session */
12725  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
12726  !parent_rel->rd_islocaltemp)
12727  ereport(ERROR,
12728  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12729  errmsg("cannot inherit from temporary relation of another session")));
12730 
12731  /* Ditto for the child */
12732  if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
12733  !child_rel->rd_islocaltemp)
12734  ereport(ERROR,
12735  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12736  errmsg("cannot inherit to temporary relation of another session")));
12737 
12738  /* Prevent partitioned tables from becoming inheritance parents */
12739  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12740  ereport(ERROR,
12741  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12742  errmsg("cannot inherit from partitioned table \"%s\"",
12743  parent->relname)));
12744 
12745  /* Likewise for partitions */
12746  if (parent_rel->rd_rel->relispartition)
12747  ereport(ERROR,
12748  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
12749  errmsg("cannot inherit from a partition")));
12750 
12751  /*
12752  * Prevent circularity by seeing if proposed parent inherits from child.
12753  * (In particular, this disallows making a rel inherit from itself.)
12754  *
12755  * This is not completely bulletproof because of race conditions: in
12756  * multi-level inheritance trees, someone else could concurrently be
12757  * making another inheritance link that closes the loop but does not join
12758  * either of the rels we have locked. Preventing that seems to require
12759  * exclusive locks on the entire inheritance tree, which is a cure worse
12760  * than the disease. find_all_inheritors() will cope with circularity
12761  * anyway, so don't sweat it too much.
12762  *
12763  * We use weakest lock we can on child's children, namely AccessShareLock.
12764  */
12765  children = find_all_inheritors(RelationGetRelid(child_rel),
12766  AccessShareLock, NULL);
12767 
12768  if (list_member_oid(children, RelationGetRelid(parent_rel)))
12769  ereport(ERROR,
12770  (errcode(ERRCODE_DUPLICATE_TABLE),
12771  errmsg("circular inheritance not allowed"),
12772  errdetail("\"%s\" is already a child of \"%s\".",
12773  parent->relname,
12774  RelationGetRelationName(child_rel))));
12775 
12776  /*
12777  * If child_rel has row-level triggers with transition tables, we
12778  * currently don't allow it to become an inheritance child. See also
12779  * prohibitions in ATExecAttachPartition() and CreateTrigger().
12780  */
12781  trigger_name = FindTriggerIncompatibleWithInheritance(child_rel->trigdesc);
12782  if (trigger_name != NULL)
12783  ereport(ERROR,
12784  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12785  errmsg("trigger \"%s\" prevents table \"%s\" from becoming an inheritance child",
12786  trigger_name, RelationGetRelationName(child_rel)),
12787  errdetail("ROW triggers with transition tables are not supported in inheritance hierarchies.")));
12788 
12789  /* OK to create inheritance */
12790  CreateInheritance(child_rel, parent_rel);
12791 
12792  ObjectAddressSet(address, RelationRelationId,
12793  RelationGetRelid(parent_rel));
12794 
12795  /* keep our lock on the parent relation until commit */
12796  table_close(parent_rel, NoLock);
12797 
12798  return address;
12799 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
bool rd_islocaltemp
Definition: rel.h:60
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:570
Form_pg_class rd_rel
Definition: rel.h:84
#define ATT_TABLE
Definition: tablecmds.c:286
static void CreateInheritance(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:12809
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:90
#define NoLock
Definition: lockdefs.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:860
#define RelationGetRelationName(relation)
Definition: rel.h:448
#define ereport(elevel, rest)
Definition: elog.h:141
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: table.c:68
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
Definition: r