PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
tablecmds.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/multixact.h"
#include "access/reloptions.h"
#include "access/relscan.h"
#include "access/sysattr.h"
#include "access/tupconvert.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_constraint_fn.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/pg_type_fn.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "catalog/toasting.h"
#include "commands/cluster.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/policy.h"
#include "commands/sequence.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
#include "commands/user.h"
#include "executor/executor.h"
#include "foreign/foreign.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/parsenodes.h"
#include "optimizer/clauses.h"
#include "optimizer/planner.h"
#include "optimizer/predtest.h"
#include "optimizer/prep.h"
#include "optimizer/var.h"
#include "parser/parse_clause.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "parser/parse_utilcmd.h"
#include "parser/parser.h"
#include "pgstat.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteHandler.h"
#include "rewrite/rewriteManip.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "storage/lock.h"
#include "storage/predicate.h"
#include "storage/smgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/relcache.h"
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
#include "utils/typcache.h"
Include dependency graph for tablecmds.c:

Go to the source code of this file.

Data Structures

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

Macros

#define AT_PASS_UNSET   -1 /* UNSET will cause ERROR */
 
#define AT_PASS_DROP   0 /* DROP (all flavors) */
 
#define AT_PASS_ALTER_TYPE   1 /* ALTER COLUMN TYPE */
 
#define AT_PASS_OLD_INDEX   2 /* re-add existing indexes */
 
#define AT_PASS_OLD_CONSTR   3 /* re-add existing constraints */
 
#define AT_PASS_COL_ATTRS   4 /* set other column attributes */
 
#define AT_PASS_ADD_COL   5 /* ADD COLUMN */
 
#define AT_PASS_ADD_INDEX   6 /* ADD indexes */
 
#define AT_PASS_ADD_CONSTR   7 /* ADD constraints, defaults */
 
#define AT_PASS_MISC   8 /* other stuff */
 
#define AT_NUM_PASSES   9
 
#define ATT_TABLE   0x0001
 
#define ATT_VIEW   0x0002
 
#define ATT_MATVIEW   0x0004
 
#define ATT_INDEX   0x0008
 
#define ATT_COMPOSITE_TYPE   0x0010
 
#define ATT_FOREIGN_TABLE   0x0020
 

Typedefs

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

Functions

static void truncate_check_rel (Relation rel)
 
static ListMergeAttributes (List *schema, List *supers, char relpersistence, bool is_partition, List **supOids, List **supconstr, int *supOidCount)
 
static bool MergeCheckConstraint (List *constraints, char *name, Node *expr)
 
static void MergeAttributesIntoExisting (Relation child_rel, Relation parent_rel)
 
static void MergeConstraintsIntoExisting (Relation child_rel, Relation parent_rel)
 
static void StoreCatalogInheritance (Oid relationId, List *supers, bool child_is_partition)
 
static void StoreCatalogInheritance1 (Oid relationId, Oid parentOid, int16 seqNumber, Relation inhRelation, bool child_is_partition)
 
static int findAttrByName (const char *attributeName, List *schema)
 
static void AlterIndexNamespaces (Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
 
static void AlterSeqNamespaces (Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, LOCKMODE lockmode)
 
static ObjectAddress ATExecAlterConstraint (Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
 
static ObjectAddress ATExecValidateConstraint (Relation rel, char *constrName, bool recurse, bool recursing, LOCKMODE lockmode)
 
static int transformColumnNameList (Oid relId, List *colList, int16 *attnums, Oid *atttypids)
 
static int transformFkeyGetPrimaryKey (Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
 
static Oid transformFkeyCheckAttrs (Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
 
static void checkFkeyPermissions (Relation rel, int16 *attnums, int natts)
 
static CoercionPathType findFkeyCast (Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
 
static void validateCheckConstraint (Relation rel, HeapTuple constrtup)
 
static void validateForeignKeyConstraint (char *conname, Relation rel, Relation pkrel, Oid pkindOid, Oid constraintOid)
 
static void createForeignKeyTriggers (Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
 
static void ATController (AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
 
static void ATPrepCmd (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
 
static void ATRewriteCatalogs (List **wqueue, LOCKMODE lockmode)
 
static void ATExecCmd (List **wqueue, AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static void ATRewriteTables (AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
 
static void ATRewriteTable (AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 
static AlteredTableInfoATGetQueueEntry (List **wqueue, Relation rel)
 
static void ATSimplePermissions (Relation rel, int allowed_targets)
 
static void ATWrongRelkindError (Relation rel, int allowed_targets)
 
static void ATSimpleRecursion (List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode)
 
static void ATTypedTableRecursion (List **wqueue, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static Listfind_typed_table_dependencies (Oid typeOid, const char *typeName, DropBehavior behavior)
 
static void ATPrepAddColumn (List **wqueue, Relation rel, bool recurse, bool recursing, bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static ObjectAddress ATExecAddColumn (List **wqueue, AlteredTableInfo *tab, Relation rel, ColumnDef *colDef, bool isOid, bool recurse, bool recursing, bool if_not_exists, LOCKMODE lockmode)
 
static bool check_for_column_name_collision (Relation rel, const char *colname, bool if_not_exists)
 
static void add_column_datatype_dependency (Oid relid, int32 attnum, Oid typid)
 
static void add_column_collation_dependency (Oid relid, int32 attnum, Oid collid)
 
static void ATPrepAddOids (List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static void ATPrepDropNotNull (Relation rel, bool recurse, bool recursing)
 
static ObjectAddress ATExecDropNotNull (Relation rel, const char *colName, LOCKMODE lockmode)
 
static void ATPrepSetNotNull (Relation rel, bool recurse, bool recursing)
 
static ObjectAddress ATExecSetNotNull (AlteredTableInfo *tab, Relation rel, const char *colName, LOCKMODE lockmode)
 
static ObjectAddress ATExecColumnDefault (Relation rel, const char *colName, Node *newDefault, LOCKMODE lockmode)
 
static void ATPrepSetStatistics (Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetStatistics (Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetOptions (Relation rel, const char *colName, Node *options, bool isReset, LOCKMODE lockmode)
 
static ObjectAddress ATExecSetStorage (Relation rel, const char *colName, Node *newValue, LOCKMODE lockmode)
 
static void ATPrepDropColumn (List **wqueue, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static ObjectAddress ATExecDropColumn (List **wqueue, Relation rel, const char *colName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode)
 
static ObjectAddress ATExecAddIndex (AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, bool is_rebuild, LOCKMODE lockmode)
 
static ObjectAddress ATExecAddConstraint (List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *newConstraint, bool recurse, bool is_readd, LOCKMODE lockmode)
 
static ObjectAddress ATExecAddIndexConstraint (AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, LOCKMODE lockmode)
 
static ObjectAddress ATAddCheckConstraint (List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
 
static ObjectAddress ATAddForeignKeyConstraint (AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, LOCKMODE lockmode)
 
static void ATExecDropConstraint (Relation rel, const char *constrName, DropBehavior behavior, bool recurse, bool recursing, bool missing_ok, LOCKMODE lockmode)
 
static void ATPrepAlterColumnType (List **wqueue, AlteredTableInfo *tab, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static bool ATColumnChangeRequiresRewrite (Node *expr, AttrNumber varattno)
 
static ObjectAddress ATExecAlterColumnType (AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode)
 
static ObjectAddress ATExecAlterColumnGenericOptions (Relation rel, const char *colName, List *options, LOCKMODE lockmode)
 
static void ATPostAlterTypeCleanup (List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
 
static void ATPostAlterTypeParse (Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, List **wqueue, LOCKMODE lockmode, bool rewrite)
 
static void RebuildConstraintComment (AlteredTableInfo *tab, int pass, Oid objid, Relation rel, 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, char *tablespacename, LOCKMODE lockmode)
 
static void ATExecSetTableSpace (Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 
static void ATExecSetRelOptions (Relation rel, List *defList, AlterTableType operation, LOCKMODE lockmode)
 
static void ATExecEnableDisableTrigger (Relation rel, char *trigname, char fires_when, bool skip_system, LOCKMODE lockmode)
 
static void ATExecEnableDisableRule (Relation rel, 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)
 
static ObjectAddress ATExecAddOf (Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
 
static void ATExecDropOf (Relation rel, LOCKMODE lockmode)
 
static void ATExecReplicaIdentity (Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
 
static void ATExecGenericOptions (Relation rel, List *options)
 
static void ATExecEnableRowSecurity (Relation rel)
 
static void ATExecDisableRowSecurity (Relation rel)
 
static void ATExecForceNoForceRowSecurity (Relation rel, bool force_rls)
 
static void copy_relation_data (SMgrRelation rel, SMgrRelation dst, ForkNumber forkNum, char relpersistence)
 
static const char * storage_name (char c)
 
static void RangeVarCallbackForDropRelation (const RangeVar *rel, Oid relOid, Oid oldRelOid, void *arg)
 
static void RangeVarCallbackForAlterRelation (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
static bool is_partition_attr (Relation rel, AttrNumber attnum, bool *used_in_expr)
 
static PartitionSpectransformPartitionSpec (Relation rel, PartitionSpec *partspec, char *strategy)
 
static void ComputePartitionAttrs (Relation rel, List *partParams, AttrNumber *partattrs, List **partexprs, Oid *partopclass, Oid *partcollation)
 
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 ObjectAddress ATExecDetachPartition (Relation rel, RangeVar *name)
 
ObjectAddress DefineRelation (CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
 
static void DropErrorMsgNonExistent (RangeVar *rel, char rightkind, bool missing_ok)
 
static void DropErrorMsgWrongType (const char *relname, char wrongkind, char rightkind)
 
void RemoveRelations (DropStmt *drop)
 
void ExecuteTruncate (TruncateStmt *stmt)
 
void SetRelationHasSubclass (Oid relationId, bool relhassubclass)
 
static void renameatt_check (Oid myrelid, Form_pg_class classform, bool recursing)
 
static AttrNumber renameatt_internal (Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing, int expected_parents, DropBehavior behavior)
 
static void RangeVarCallbackForRenameAttribute (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
ObjectAddress renameatt (RenameStmt *stmt)
 
static ObjectAddress rename_constraint_internal (Oid myrelid, Oid mytypid, const char *oldconname, const char *newconname, bool recurse, bool recursing, int expected_parents)
 
ObjectAddress RenameConstraint (RenameStmt *stmt)
 
ObjectAddress RenameRelation (RenameStmt *stmt)
 
void RenameRelationInternal (Oid myrelid, const char *newrelname, bool is_internal)
 
void CheckTableNotInUse (Relation rel, const char *stmt)
 
Oid AlterTableLookupRelation (AlterTableStmt *stmt, LOCKMODE lockmode)
 
void AlterTable (Oid relid, LOCKMODE lockmode, AlterTableStmt *stmt)
 
void AlterTableInternal (Oid relid, List *cmds, bool recurse)
 
LOCKMODE AlterTableGetLockLevel (List *cmds)
 
void find_composite_type_dependencies (Oid typeOid, Relation origRelation, const char *origTypeName)
 
void check_of_type (HeapTuple typetuple)
 
static void CreateFKCheckTrigger (Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid, bool on_insert)
 
void ATExecChangeOwner (Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
 
Oid AlterTableMoveAll (AlterTableMoveAllStmt *stmt)
 
static char * decompile_conbin (HeapTuple contup, TupleDesc tupdesc)
 
static bool constraints_equivalent (HeapTuple a, HeapTuple b, TupleDesc tupleDesc)
 
static void relation_mark_replica_identity (Relation rel, char ri_type, Oid indexOid, bool is_internal)
 
ObjectAddress AlterTableNamespace (AlterObjectSchemaStmt *stmt, Oid *oldschema)
 
void AlterTableNamespaceInternal (Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
 
void AlterRelationNamespaceInternal (Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
 
void register_on_commit_action (Oid relid, OnCommitAction action)
 
void remove_on_commit_action (Oid relid)
 
void PreCommit_on_commit_actions (void)
 
void AtEOXact_on_commit_actions (bool isCommit)
 
void AtEOSubXact_on_commit_actions (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
void RangeVarCallbackOwnsTable (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 
void RangeVarCallbackOwnsRelation (const RangeVar *relation, Oid relId, Oid oldRelId, void *arg)
 

Variables

static Liston_commits = NIL
 
static const struct dropmsgstrings dropmsgstringarray []
 

Macro Definition Documentation

#define AT_NUM_PASSES   9

Definition at line 152 of file tablecmds.c.

Referenced by ATRewriteCatalogs().

#define AT_PASS_ADD_COL   5 /* ADD COLUMN */

Definition at line 148 of file tablecmds.c.

Referenced by ATPrepCmd().

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

Definition at line 150 of file tablecmds.c.

Referenced by ATPrepCmd().

#define AT_PASS_ADD_INDEX   6 /* ADD indexes */

Definition at line 149 of file tablecmds.c.

Referenced by ATPrepCmd().

#define AT_PASS_ALTER_TYPE   1 /* ALTER COLUMN TYPE */

Definition at line 143 of file tablecmds.c.

Referenced by ATPrepCmd(), and ATRewriteCatalogs().

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

Definition at line 146 of file tablecmds.c.

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

Definition at line 142 of file tablecmds.c.

Referenced by ATPrepCmd().

#define AT_PASS_MISC   8 /* other stuff */

Definition at line 151 of file tablecmds.c.

Referenced by ATPrepCmd().

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

Definition at line 145 of file tablecmds.c.

Referenced by ATPostAlterTypeParse().

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

Definition at line 144 of file tablecmds.c.

Referenced by ATPostAlterTypeParse().

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

Definition at line 141 of file tablecmds.c.

Referenced by ATPrepCmd().

#define ATT_COMPOSITE_TYPE   0x0010

Definition at line 282 of file tablecmds.c.

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

#define ATT_INDEX   0x0008

Definition at line 281 of file tablecmds.c.

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

#define ATT_MATVIEW   0x0004

Definition at line 280 of file tablecmds.c.

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

#define ATT_VIEW   0x0002

Definition at line 279 of file tablecmds.c.

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

Typedef Documentation

Function Documentation

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

Definition at line 5443 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

5444 {
5445  ObjectAddress myself,
5446  referenced;
5447 
5448  /* We know the default collation is pinned, so don't bother recording it */
5449  if (OidIsValid(collid) && collid != DEFAULT_COLLATION_OID)
5450  {
5451  myself.classId = RelationRelationId;
5452  myself.objectId = relid;
5453  myself.objectSubId = attnum;
5454  referenced.classId = CollationRelationId;
5455  referenced.objectId = collid;
5456  referenced.objectSubId = 0;
5457  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
5458  }
5459 }
#define RelationRelationId
Definition: pg_class.h:29
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
#define OidIsValid(objectId)
Definition: c.h:538
#define DEFAULT_COLLATION_OID
Definition: pg_collation.h:74
#define CollationRelationId
Definition: pg_collation.h:30
static void add_column_datatype_dependency ( Oid  relid,
int32  attnum,
Oid  typid 
)
static

Definition at line 5425 of file tablecmds.c.

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

Referenced by ATExecAddColumn(), and ATExecAlterColumnType().

5426 {
5427  ObjectAddress myself,
5428  referenced;
5429 
5430  myself.classId = RelationRelationId;
5431  myself.objectId = relid;
5432  myself.objectSubId = attnum;
5433  referenced.classId = TypeRelationId;
5434  referenced.objectId = typid;
5435  referenced.objectSubId = 0;
5436  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
5437 }
#define RelationRelationId
Definition: pg_class.h:29
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
#define TypeRelationId
Definition: pg_type.h:34
static void AlterIndexNamespaces ( Relation  classRel,
Relation  rel,
Oid  oldNspOid,
Oid  newNspOid,
ObjectAddresses objsMoved 
)
static

Definition at line 12259 of file tablecmds.c.

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

Referenced by AlterTableNamespaceInternal().

12261 {
12262  List *indexList;
12263  ListCell *l;
12264 
12265  indexList = RelationGetIndexList(rel);
12266 
12267  foreach(l, indexList)
12268  {
12269  Oid indexOid = lfirst_oid(l);
12270  ObjectAddress thisobj;
12271 
12272  thisobj.classId = RelationRelationId;
12273  thisobj.objectId = indexOid;
12274  thisobj.objectSubId = 0;
12275 
12276  /*
12277  * Note: currently, the index will not have its own dependency on the
12278  * namespace, so we don't need to do changeDependencyFor(). There's no
12279  * row type in pg_type, either.
12280  *
12281  * XXX this objsMoved test may be pointless -- surely we have a single
12282  * dependency link from a relation to each index?
12283  */
12284  if (!object_address_present(&thisobj, objsMoved))
12285  {
12286  AlterRelationNamespaceInternal(classRel, indexOid,
12287  oldNspOid, newNspOid,
12288  false, objsMoved);
12289  add_exact_object_address(&thisobj, objsMoved);
12290  }
12291  }
12292 
12293  list_free(indexList);
12294 }
#define RelationRelationId
Definition: pg_class.h:29
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2147
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2087
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:12189
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4337
void list_free(List *list)
Definition: list.c:1133
Definition: pg_list.h:45
#define lfirst_oid(lc)
Definition: pg_list.h:108
void AlterRelationNamespaceInternal ( Relation  classRel,
Oid  relOid,
Oid  oldNspOid,
Oid  newNspOid,
bool  hasDependEntry,
ObjectAddresses objsMoved 
)

Definition at line 12189 of file tablecmds.c.

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

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

12193 {
12194  HeapTuple classTup;
12195  Form_pg_class classForm;
12196  ObjectAddress thisobj;
12197  bool already_done = false;
12198 
12199  classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
12200  if (!HeapTupleIsValid(classTup))
12201  elog(ERROR, "cache lookup failed for relation %u", relOid);
12202  classForm = (Form_pg_class) GETSTRUCT(classTup);
12203 
12204  Assert(classForm->relnamespace == oldNspOid);
12205 
12206  thisobj.classId = RelationRelationId;
12207  thisobj.objectId = relOid;
12208  thisobj.objectSubId = 0;
12209 
12210  /*
12211  * If the object has already been moved, don't move it again. If it's
12212  * already in the right place, don't move it, but still fire the object
12213  * access hook.
12214  */
12215  already_done = object_address_present(&thisobj, objsMoved);
12216  if (!already_done && oldNspOid != newNspOid)
12217  {
12218  /* check for duplicate name (more friendly than unique-index failure) */
12219  if (get_relname_relid(NameStr(classForm->relname),
12220  newNspOid) != InvalidOid)
12221  ereport(ERROR,
12222  (errcode(ERRCODE_DUPLICATE_TABLE),
12223  errmsg("relation \"%s\" already exists in schema \"%s\"",
12224  NameStr(classForm->relname),
12225  get_namespace_name(newNspOid))));
12226 
12227  /* classTup is a copy, so OK to scribble on */
12228  classForm->relnamespace = newNspOid;
12229 
12230  CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
12231 
12232  /* Update dependency on schema if caller said so */
12233  if (hasDependEntry &&
12235  relOid,
12237  oldNspOid,
12238  newNspOid) != 1)
12239  elog(ERROR, "failed to change schema dependency for relation \"%s\"",
12240  NameStr(classForm->relname));
12241  }
12242  if (!already_done)
12243  {
12244  add_exact_object_address(&thisobj, objsMoved);
12245 
12247  }
12248 
12249  heap_freetuple(classTup);
12250 }
#define NamespaceRelationId
Definition: pg_namespace.h:34
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define RelationRelationId
Definition: pg_class.h:29
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2147
int errcode(int sqlerrcode)
Definition: elog.c:575
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2087
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1651
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3006
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:675
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:161
int errmsg(const char *fmt,...)
Definition: elog.c:797
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:295
#define NameStr(name)
Definition: c.h:499
#define elog
Definition: elog.h:219
static void AlterSeqNamespaces ( Relation  classRel,
Relation  rel,
Oid  oldNspOid,
Oid  newNspOid,
ObjectAddresses objsMoved,
LOCKMODE  lockmode 
)
static

Definition at line 12304 of file tablecmds.c.

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

Referenced by AlterTableNamespaceInternal().

12307 {
12308  Relation depRel;
12309  SysScanDesc scan;
12310  ScanKeyData key[2];
12311  HeapTuple tup;
12312 
12313  /*
12314  * SERIAL sequences are those having an auto dependency on one of the
12315  * table's columns (we don't care *which* column, exactly).
12316  */
12318 
12319  ScanKeyInit(&key[0],
12321  BTEqualStrategyNumber, F_OIDEQ,
12323  ScanKeyInit(&key[1],
12325  BTEqualStrategyNumber, F_OIDEQ,
12327  /* we leave refobjsubid unspecified */
12328 
12329  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
12330  NULL, 2, key);
12331 
12332  while (HeapTupleIsValid(tup = systable_getnext(scan)))
12333  {
12334  Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
12335  Relation seqRel;
12336 
12337  /* skip dependencies other than auto dependencies on columns */
12338  if (depForm->refobjsubid == 0 ||
12339  depForm->classid != RelationRelationId ||
12340  depForm->objsubid != 0 ||
12341  depForm->deptype != DEPENDENCY_AUTO)
12342  continue;
12343 
12344  /* Use relation_open just in case it's an index */
12345  seqRel = relation_open(depForm->objid, lockmode);
12346 
12347  /* skip non-sequence relations */
12348  if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
12349  {
12350  /* No need to keep the lock */
12351  relation_close(seqRel, lockmode);
12352  continue;
12353  }
12354 
12355  /* Fix the pg_class and pg_depend entries */
12356  AlterRelationNamespaceInternal(classRel, depForm->objid,
12357  oldNspOid, newNspOid,
12358  true, objsMoved);
12359 
12360  /*
12361  * Sequences have entries in pg_type. We need to be careful to move
12362  * them to the new namespace, too.
12363  */
12365  newNspOid, false, false, objsMoved);
12366 
12367  /* Now we can close it. Keep the lock till end of transaction. */
12368  relation_close(seqRel, NoLock);
12369  }
12370 
12371  systable_endscan(scan);
12372 
12374 }
#define Anum_pg_depend_refobjid
Definition: pg_depend.h:72
#define Anum_pg_depend_refclassid
Definition: pg_depend.h:71
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define RelationGetForm(relation)
Definition: rel.h:411
#define RelationRelationId
Definition: pg_class.h:29
#define DependReferenceIndexId
Definition: indexing.h:147
#define DependRelationId
Definition: pg_depend.h:29
#define AccessShareLock
Definition: lockdefs.h:36
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3491
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1263
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define NoLock
Definition: lockdefs.h:34
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:61
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12189
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1117
#define RELKIND_SEQUENCE
Definition: pg_class.h:162
#define RelationGetRelid(relation)
Definition: rel.h:417
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void AlterTable ( Oid  relid,
LOCKMODE  lockmode,
AlterTableStmt stmt 
)

Definition at line 3049 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3050 {
3051  Relation rel;
3052 
3053  /* Caller is required to provide an adequate lock. */
3054  rel = relation_open(relid, NoLock);
3055 
3056  CheckTableNotInUse(rel, "ALTER TABLE");
3057 
3058  ATController(stmt, rel, stmt->cmds, stmt->relation->inh, lockmode);
3059 }
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3364
#define NoLock
Definition: lockdefs.h:34
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:2970
bool inh
Definition: primnodes.h:69
RangeVar * relation
Definition: parsenodes.h:1641
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1117
LOCKMODE AlterTableGetLockLevel ( List cmds)

Definition at line 3118 of file tablecmds.c.

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

3119 {
3120  /*
3121  * This only works if we read catalog tables using MVCC snapshots.
3122  */
3123  ListCell *lcmd;
3125 
3126  foreach(lcmd, cmds)
3127  {
3128  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3129  LOCKMODE cmd_lockmode = AccessExclusiveLock; /* default for compiler */
3130 
3131  switch (cmd->subtype)
3132  {
3133  /*
3134  * These subcommands rewrite the heap, so require full locks.
3135  */
3136  case AT_AddColumn: /* may rewrite heap, in some cases and visible
3137  * to SELECT */
3138  case AT_SetTableSpace: /* must rewrite heap */
3139  case AT_AlterColumnType: /* must rewrite heap */
3140  case AT_AddOids: /* must rewrite heap */
3141  cmd_lockmode = AccessExclusiveLock;
3142  break;
3143 
3144  /*
3145  * These subcommands may require addition of toast tables. If
3146  * we add a toast table to a table currently being scanned, we
3147  * might miss data added to the new toast table by concurrent
3148  * insert transactions.
3149  */
3150  case AT_SetStorage:/* may add toast tables, see
3151  * ATRewriteCatalogs() */
3152  cmd_lockmode = AccessExclusiveLock;
3153  break;
3154 
3155  /*
3156  * Removing constraints can affect SELECTs that have been
3157  * optimised assuming the constraint holds true.
3158  */
3159  case AT_DropConstraint: /* as DROP INDEX */
3160  case AT_DropNotNull: /* may change some SQL plans */
3161  cmd_lockmode = AccessExclusiveLock;
3162  break;
3163 
3164  /*
3165  * Subcommands that may be visible to concurrent SELECTs
3166  */
3167  case AT_DropColumn: /* change visible to SELECT */
3168  case AT_AddColumnToView: /* CREATE VIEW */
3169  case AT_DropOids: /* calls AT_DropColumn */
3170  case AT_EnableAlwaysRule: /* may change SELECT rules */
3171  case AT_EnableReplicaRule: /* may change SELECT rules */
3172  case AT_EnableRule: /* may change SELECT rules */
3173  case AT_DisableRule: /* may change SELECT rules */
3174  cmd_lockmode = AccessExclusiveLock;
3175  break;
3176 
3177  /*
3178  * Changing owner may remove implicit SELECT privileges
3179  */
3180  case AT_ChangeOwner: /* change visible to SELECT */
3181  cmd_lockmode = AccessExclusiveLock;
3182  break;
3183 
3184  /*
3185  * Changing foreign table options may affect optimization.
3186  */
3187  case AT_GenericOptions:
3189  cmd_lockmode = AccessExclusiveLock;
3190  break;
3191 
3192  /*
3193  * These subcommands affect write operations only.
3194  */
3195  case AT_EnableTrig:
3196  case AT_EnableAlwaysTrig:
3197  case AT_EnableReplicaTrig:
3198  case AT_EnableTrigAll:
3199  case AT_EnableTrigUser:
3200  case AT_DisableTrig:
3201  case AT_DisableTrigAll:
3202  case AT_DisableTrigUser:
3203  cmd_lockmode = ShareRowExclusiveLock;
3204  break;
3205 
3206  /*
3207  * These subcommands affect write operations only. XXX
3208  * Theoretically, these could be ShareRowExclusiveLock.
3209  */
3210  case AT_ColumnDefault:
3211  case AT_AlterConstraint:
3212  case AT_AddIndex: /* from ADD CONSTRAINT */
3213  case AT_AddIndexConstraint:
3214  case AT_ReplicaIdentity:
3215  case AT_SetNotNull:
3216  case AT_EnableRowSecurity:
3217  case AT_DisableRowSecurity:
3218  case AT_ForceRowSecurity:
3219  case AT_NoForceRowSecurity:
3220  cmd_lockmode = AccessExclusiveLock;
3221  break;
3222 
3223  case AT_AddConstraint:
3224  case AT_ProcessedConstraint: /* becomes AT_AddConstraint */
3225  case AT_AddConstraintRecurse: /* becomes AT_AddConstraint */
3226  case AT_ReAddConstraint: /* becomes AT_AddConstraint */
3227  if (IsA(cmd->def, Constraint))
3228  {
3229  Constraint *con = (Constraint *) cmd->def;
3230 
3231  switch (con->contype)
3232  {
3233  case CONSTR_EXCLUSION:
3234  case CONSTR_PRIMARY:
3235  case CONSTR_UNIQUE:
3236 
3237  /*
3238  * Cases essentially the same as CREATE INDEX. We
3239  * could reduce the lock strength to ShareLock if
3240  * we can work out how to allow concurrent catalog
3241  * updates. XXX Might be set down to
3242  * ShareRowExclusiveLock but requires further
3243  * analysis.
3244  */
3245  cmd_lockmode = AccessExclusiveLock;
3246  break;
3247  case CONSTR_FOREIGN:
3248 
3249  /*
3250  * We add triggers to both tables when we add a
3251  * Foreign Key, so the lock level must be at least
3252  * as strong as CREATE TRIGGER.
3253  */
3254  cmd_lockmode = ShareRowExclusiveLock;
3255  break;
3256 
3257  default:
3258  cmd_lockmode = AccessExclusiveLock;
3259  }
3260  }
3261  break;
3262 
3263  /*
3264  * These subcommands affect inheritance behaviour. Queries
3265  * started before us will continue to see the old inheritance
3266  * behaviour, while queries started after we commit will see
3267  * new behaviour. No need to prevent reads or writes to the
3268  * subtable while we hook it up though. Changing the TupDesc
3269  * may be a problem, so keep highest lock.
3270  */
3271  case AT_AddInherit:
3272  case AT_DropInherit:
3273  cmd_lockmode = AccessExclusiveLock;
3274  break;
3275 
3276  /*
3277  * These subcommands affect implicit row type conversion. They
3278  * have affects similar to CREATE/DROP CAST on queries. don't
3279  * provide for invalidating parse trees as a result of such
3280  * changes, so we keep these at AccessExclusiveLock.
3281  */
3282  case AT_AddOf:
3283  case AT_DropOf:
3284  cmd_lockmode = AccessExclusiveLock;
3285  break;
3286 
3287  /*
3288  * Only used by CREATE OR REPLACE VIEW which must conflict
3289  * with an SELECTs currently using the view.
3290  */
3291  case AT_ReplaceRelOptions:
3292  cmd_lockmode = AccessExclusiveLock;
3293  break;
3294 
3295  /*
3296  * These subcommands affect general strategies for performance
3297  * and maintenance, though don't change the semantic results
3298  * from normal data reads and writes. Delaying an ALTER TABLE
3299  * behind currently active writes only delays the point where
3300  * the new strategy begins to take effect, so there is no
3301  * benefit in waiting. In this case the minimum restriction
3302  * applies: we don't currently allow concurrent catalog
3303  * updates.
3304  */
3305  case AT_SetStatistics: /* Uses MVCC in getTableAttrs() */
3306  case AT_ClusterOn: /* Uses MVCC in getIndexes() */
3307  case AT_DropCluster: /* Uses MVCC in getIndexes() */
3308  case AT_SetOptions: /* Uses MVCC in getTableAttrs() */
3309  case AT_ResetOptions: /* Uses MVCC in getTableAttrs() */
3310  cmd_lockmode = ShareUpdateExclusiveLock;
3311  break;
3312 
3313  case AT_SetLogged:
3314  case AT_SetUnLogged:
3315  cmd_lockmode = AccessExclusiveLock;
3316  break;
3317 
3318  case AT_ValidateConstraint: /* Uses MVCC in
3319  * getConstraints() */
3320  cmd_lockmode = ShareUpdateExclusiveLock;
3321  break;
3322 
3323  /*
3324  * Rel options are more complex than first appears. Options
3325  * are set here for tables, views and indexes; for historical
3326  * reasons these can all be used with ALTER TABLE, so we can't
3327  * decide between them using the basic grammar.
3328  */
3329  case AT_SetRelOptions: /* Uses MVCC in getIndexes() and
3330  * getTables() */
3331  case AT_ResetRelOptions: /* Uses MVCC in getIndexes() and
3332  * getTables() */
3333  cmd_lockmode = AlterTableGetRelOptionsLockLevel((List *) cmd->def);
3334  break;
3335 
3336  case AT_AttachPartition:
3337  case AT_DetachPartition:
3338  cmd_lockmode = AccessExclusiveLock;
3339  break;
3340 
3341  default: /* oops */
3342  elog(ERROR, "unrecognized alter table type: %d",
3343  (int) cmd->subtype);
3344  break;
3345  }
3346 
3347  /*
3348  * Take the greatest lockmode from any subcommand
3349  */
3350  if (cmd_lockmode > lockmode)
3351  lockmode = cmd_lockmode;
3352  }
3353 
3354  return lockmode;
3355 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:555
int LOCKMODE
Definition: lockdefs.h:26
AlterTableType subtype
Definition: parsenodes.h:1725
#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:1519
#define AccessExclusiveLock
Definition: lockdefs.h:46
ConstrType contype
Definition: parsenodes.h:2025
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
void AlterTableInternal ( Oid  relid,
List cmds,
bool  recurse 
)

Definition at line 3073 of file tablecmds.c.

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

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

3074 {
3075  Relation rel;
3076  LOCKMODE lockmode = AlterTableGetLockLevel(cmds);
3077 
3078  rel = relation_open(relid, lockmode);
3079 
3081 
3082  ATController(NULL, rel, cmds, recurse, lockmode);
3083 }
int LOCKMODE
Definition: lockdefs.h:26
static void ATController(AlterTableStmt *parsetree, Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
Definition: tablecmds.c:3364
LOCKMODE AlterTableGetLockLevel(List *cmds)
Definition: tablecmds.c:3118
#define NULL
Definition: c.h:229
void EventTriggerAlterTableRelid(Oid objectId)
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1117
Oid AlterTableLookupRelation ( AlterTableStmt stmt,
LOCKMODE  lockmode 
)

Definition at line 2999 of file tablecmds.c.

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

Referenced by ProcessUtilitySlow().

3000 {
3001  return RangeVarGetRelidExtended(stmt->relation, lockmode, stmt->missing_ok, false,
3003  (void *) stmt);
3004 }
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:217
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:12666
RangeVar * relation
Definition: parsenodes.h:1641
Oid AlterTableMoveAll ( AlterTableMoveAllStmt stmt)

Definition at line 10289 of file tablecmds.c.

References AccessExclusiveLock, AccessShareLock, ACL_CREATE, ACL_KIND_CLASS, ACL_KIND_TABLESPACE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTableInternal(), Anum_pg_class_reltablespace, AT_SetTableSpace, BTEqualStrategyNumber, ConditionalLockRelationOid(), ereport, errcode(), errmsg(), ERROR, EventTriggerAlterTableEnd(), EventTriggerAlterTableStart(), ForwardScanDirection, get_namespace_name(), get_tablespace_name(), get_tablespace_oid(), GETSTRUCT, GetUserId(), GLOBALTABLESPACE_OID, heap_beginscan_catalog(), heap_close, heap_endscan(), heap_getnext(), heap_open(), HeapTupleGetOid, InvalidOid, isAnyTempNamespace(), IsSystemNamespace(), lappend(), lappend_oid(), lfirst_oid, list_member_oid(), LockRelationOid(), makeNode, MyDatabaseTableSpace, AlterTableCmd::name, NameStr, AlterTableMoveAllStmt::new_tablespacename, NIL, NOTICE, AlterTableMoveAllStmt::nowait, NULL, OBJECT_INDEX, OBJECT_MATVIEW, OBJECT_TABLE, ObjectIdGetDatum, AlterTableMoveAllStmt::objtype, OidIsValid, AlterTableMoveAllStmt::orig_tablespacename, pg_class_ownercheck(), pg_tablespace_aclcheck(), PG_TOAST_NAMESPACE, RelationRelationId, RELKIND_INDEX, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, AlterTableMoveAllStmt::roles, roleSpecsToIds(), ScanKeyInit(), and AlterTableCmd::subtype.

Referenced by ProcessUtilitySlow().

10290 {
10291  List *relations = NIL;
10292  ListCell *l;
10293  ScanKeyData key[1];
10294  Relation rel;
10295  HeapScanDesc scan;
10296  HeapTuple tuple;
10297  Oid orig_tablespaceoid;
10298  Oid new_tablespaceoid;
10299  List *role_oids = roleSpecsToIds(stmt->roles);
10300 
10301  /* Ensure we were not asked to move something we can't */
10302  if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
10303  stmt->objtype != OBJECT_MATVIEW)
10304  ereport(ERROR,
10305  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
10306  errmsg("only tables, indexes, and materialized views exist in tablespaces")));
10307 
10308  /* Get the orig and new tablespace OIDs */
10309  orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false);
10310  new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false);
10311 
10312  /* Can't move shared relations in to or out of pg_global */
10313  /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */
10314  if (orig_tablespaceoid == GLOBALTABLESPACE_OID ||
10315  new_tablespaceoid == GLOBALTABLESPACE_OID)
10316  ereport(ERROR,
10317  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
10318  errmsg("cannot move relations in to or out of pg_global tablespace")));
10319 
10320  /*
10321  * Must have CREATE rights on the new tablespace, unless it is the
10322  * database default tablespace (which all users implicitly have CREATE
10323  * rights on).
10324  */
10325  if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace)
10326  {
10327  AclResult aclresult;
10328 
10329  aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(),
10330  ACL_CREATE);
10331  if (aclresult != ACLCHECK_OK)
10333  get_tablespace_name(new_tablespaceoid));
10334  }
10335 
10336  /*
10337  * Now that the checks are done, check if we should set either to
10338  * InvalidOid because it is our database's default tablespace.
10339  */
10340  if (orig_tablespaceoid == MyDatabaseTableSpace)
10341  orig_tablespaceoid = InvalidOid;
10342 
10343  if (new_tablespaceoid == MyDatabaseTableSpace)
10344  new_tablespaceoid = InvalidOid;
10345 
10346  /* no-op */
10347  if (orig_tablespaceoid == new_tablespaceoid)
10348  return new_tablespaceoid;
10349 
10350  /*
10351  * Walk the list of objects in the tablespace and move them. This will
10352  * only find objects in our database, of course.
10353  */
10354  ScanKeyInit(&key[0],
10356  BTEqualStrategyNumber, F_OIDEQ,
10357  ObjectIdGetDatum(orig_tablespaceoid));
10358 
10360  scan = heap_beginscan_catalog(rel, 1, key);
10361  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
10362  {
10363  Oid relOid = HeapTupleGetOid(tuple);
10364  Form_pg_class relForm;
10365 
10366  relForm = (Form_pg_class) GETSTRUCT(tuple);
10367 
10368  /*
10369  * Do not move objects in pg_catalog as part of this, if an admin
10370  * really wishes to do so, they can issue the individual ALTER
10371  * commands directly.
10372  *
10373  * Also, explicitly avoid any shared tables, temp tables, or TOAST
10374  * (TOAST will be moved with the main table).
10375  */
10376  if (IsSystemNamespace(relForm->relnamespace) || relForm->relisshared ||
10377  isAnyTempNamespace(relForm->relnamespace) ||
10378  relForm->relnamespace == PG_TOAST_NAMESPACE)
10379  continue;
10380 
10381  /* Only move the object type requested */
10382  if ((stmt->objtype == OBJECT_TABLE &&
10383  relForm->relkind != RELKIND_RELATION &&
10384  relForm->relkind != RELKIND_PARTITIONED_TABLE) ||
10385  (stmt->objtype == OBJECT_INDEX &&
10386  relForm->relkind != RELKIND_INDEX) ||
10387  (stmt->objtype == OBJECT_MATVIEW &&
10388  relForm->relkind != RELKIND_MATVIEW))
10389  continue;
10390 
10391  /* Check if we are only moving objects owned by certain roles */
10392  if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner))
10393  continue;
10394 
10395  /*
10396  * Handle permissions-checking here since we are locking the tables
10397  * and also to avoid doing a bunch of work only to fail part-way. Note
10398  * that permissions will also be checked by AlterTableInternal().
10399  *
10400  * Caller must be considered an owner on the table to move it.
10401  */
10402  if (!pg_class_ownercheck(relOid, GetUserId()))
10404  NameStr(relForm->relname));
10405 
10406  if (stmt->nowait &&
10408  ereport(ERROR,
10409  (errcode(ERRCODE_OBJECT_IN_USE),
10410  errmsg("aborting because lock on relation \"%s.%s\" is not available",
10411  get_namespace_name(relForm->relnamespace),
10412  NameStr(relForm->relname))));
10413  else
10415 
10416  /* Add to our list of objects to move */
10417  relations = lappend_oid(relations, relOid);
10418  }
10419 
10420  heap_endscan(scan);
10422 
10423  if (relations == NIL)
10424  ereport(NOTICE,
10425  (errcode(ERRCODE_NO_DATA_FOUND),
10426  errmsg("no matching relations in tablespace \"%s\" found",
10427  orig_tablespaceoid == InvalidOid ? "(database default)" :
10428  get_tablespace_name(orig_tablespaceoid))));
10429 
10430  /* Everything is locked, loop through and move all of the relations. */
10431  foreach(l, relations)
10432  {
10433  List *cmds = NIL;
10435 
10436  cmd->subtype = AT_SetTableSpace;
10437  cmd->name = stmt->new_tablespacename;
10438 
10439  cmds = lappend(cmds, cmd);
10440 
10442  /* OID is set by AlterTableInternal */
10443  AlterTableInternal(lfirst_oid(l), cmds, false);
10445  }
10446 
10447  return new_tablespaceoid;
10448 }
#define NIL
Definition: pg_list.h:69
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:138
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1380
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4479
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1581
Oid GetUserId(void)
Definition: miscinit.c:283
#define RelationRelationId
Definition: pg_class.h:29
#define Anum_pg_class_reltablespace
Definition: pg_class.h:110
#define RELKIND_MATVIEW
Definition: pg_class.h:165
#define AccessShareLock
Definition: lockdefs.h:36
#define GLOBALTABLESPACE_OID
Definition: pg_tablespace.h:64
Definition: nodes.h:504
int errcode(int sqlerrcode)
Definition: elog.c:575
AlterTableType subtype
Definition: parsenodes.h:1725
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
#define PG_TOAST_NAMESPACE
Definition: pg_namespace.h:74
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:538
Oid MyDatabaseTableSpace
Definition: globals.c:78
void EventTriggerAlterTableStart(Node *parsetree)
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:75
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3006
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3382
HeapScanDesc heap_beginscan_catalog(Relation relation, int nkeys, ScanKey key)
Definition: heapam.c:1402
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
AclResult
Definition: acl.h:170
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1797
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
bool IsSystemNamespace(Oid namespaceId)
Definition: catalog.c:162
#define InvalidOid
Definition: postgres_ext.h:36
#define NOTICE
Definition: elog.h:37
#define makeNode(_type_)
Definition: nodes.h:552
List * roleSpecsToIds(List *memberNames)
Definition: user.c:1384
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define NULL
Definition: c.h:229
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4529
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
void AlterTableInternal(Oid relid, List *cmds, bool recurse)
Definition: tablecmds.c:3073
#define AccessExclusiveLock
Definition: lockdefs.h:46
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1426
#define NameStr(name)
Definition: c.h:499
#define RELKIND_INDEX
Definition: pg_class.h:161
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3046
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
#define RELKIND_RELATION
Definition: pg_class.h:160
Definition: pg_list.h:45
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:108
void EventTriggerAlterTableEnd(void)
ObjectAddress AlterTableNamespace ( AlterObjectSchemaStmt stmt,
Oid oldschema 
)

Definition at line 12081 of file tablecmds.c.

References AccessExclusiveLock, AlterTableNamespaceInternal(), CheckSetNamespace(), ereport, errcode(), errdetail(), errmsg(), ERROR, free_object_addresses(), get_rel_name(), InvalidObjectAddress, makeRangeVar(), AlterObjectSchemaStmt::missing_ok, new_object_addresses(), AlterObjectSchemaStmt::newschema, NoLock, NOTICE, NULL, ObjectAddressSet, OidIsValid, RangeVarCallbackForAlterRelation(), RangeVarGetAndCheckCreationNamespace(), RangeVarGetRelidExtended(), RelationData::rd_rel, AlterObjectSchemaStmt::relation, relation_close(), relation_open(), RelationGetNamespace, RelationGetRelationName, RelationRelationId, RELKIND_SEQUENCE, RangeVar::relname, and sequenceIsOwned().

Referenced by ExecAlterObjectSchemaStmt().

12082 {
12083  Relation rel;
12084  Oid relid;
12085  Oid oldNspOid;
12086  Oid nspOid;
12087  RangeVar *newrv;
12088  ObjectAddresses *objsMoved;
12089  ObjectAddress myself;
12090 
12092  stmt->missing_ok, false,
12094  (void *) stmt);
12095 
12096  if (!OidIsValid(relid))
12097  {
12098  ereport(NOTICE,
12099  (errmsg("relation \"%s\" does not exist, skipping",
12100  stmt->relation->relname)));
12101  return InvalidObjectAddress;
12102  }
12103 
12104  rel = relation_open(relid, NoLock);
12105 
12106  oldNspOid = RelationGetNamespace(rel);
12107 
12108  /* If it's an owned sequence, disallow moving it by itself. */
12109  if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
12110  {
12111  Oid tableId;
12112  int32 colId;
12113 
12114  if (sequenceIsOwned(relid, &tableId, &colId))
12115  ereport(ERROR,
12116  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12117  errmsg("cannot move an owned sequence into another schema"),
12118  errdetail("Sequence \"%s\" is linked to table \"%s\".",
12120  get_rel_name(tableId))));
12121  }
12122 
12123  /* Get and lock schema OID and check its permissions. */
12124  newrv = makeRangeVar(stmt->newschema, RelationGetRelationName(rel), -1);
12126 
12127  /* common checks on switching namespaces */
12128  CheckSetNamespace(oldNspOid, nspOid);
12129 
12130  objsMoved = new_object_addresses();
12131  AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
12132  free_object_addresses(objsMoved);
12133 
12134  ObjectAddressSet(myself, RelationRelationId, relid);
12135 
12136  if (oldschema)
12137  *oldschema = oldNspOid;
12138 
12139  /* close rel, but keep lock until commit */
12140  relation_close(rel, NoLock);
12141 
12142  return myself;
12143 }
bool sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
Definition: pg_depend.c:500
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:217
#define RelationRelationId
Definition: pg_class.h:29
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1263
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2032
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2303
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
signed int int32
Definition: c.h:256
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:43
void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12151
#define NoLock
Definition: lockdefs.h:34
static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: tablecmds.c:12666
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define RelationGetRelationName(relation)
Definition: rel.h:437
#define ereport(elevel, rest)
Definition: elog.h:122
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2818
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:507
#define NOTICE
Definition: elog.h:37
#define NULL
Definition: c.h:229
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define AccessExclusiveLock
Definition: lockdefs.h:46
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1117
#define RELKIND_SEQUENCE
Definition: pg_class.h:162
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1694
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:419
#define RelationGetNamespace(relation)
Definition: rel.h:444
void AlterTableNamespaceInternal ( Relation  rel,
Oid  oldNspOid,
Oid  nspOid,
ObjectAddresses objsMoved 
)

Definition at line 12151 of file tablecmds.c.

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

Referenced by AlterObjectNamespace_oid(), and AlterTableNamespace().

12153 {
12154  Relation classRel;
12155 
12156  Assert(objsMoved != NULL);
12157 
12158  /* OK, modify the pg_class row and pg_depend entry */
12160 
12161  AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid,
12162  nspOid, true, objsMoved);
12163 
12164  /* Fix the table's row type too */
12165  AlterTypeNamespaceInternal(rel->rd_rel->reltype,
12166  nspOid, false, false, objsMoved);
12167 
12168  /* Fix other dependent stuff */
12169  if (rel->rd_rel->relkind == RELKIND_RELATION ||
12170  rel->rd_rel->relkind == RELKIND_MATVIEW ||
12171  rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
12172  {
12173  AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
12174  AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
12175  objsMoved, AccessExclusiveLock);
12176  AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
12177  false, objsMoved);
12178  }
12179 
12180  heap_close(classRel, RowExclusiveLock);
12181 }
#define RelationRelationId
Definition: pg_class.h:29
#define RELKIND_MATVIEW
Definition: pg_class.h:165
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3491
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12259
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:12304
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12189
#define AccessExclusiveLock
Definition: lockdefs.h:46
#define RELKIND_RELATION
Definition: pg_class.h:160
#define RelationGetRelid(relation)
Definition: rel.h:417
static ObjectAddress ATAddCheckConstraint ( List **  wqueue,
AlteredTableInfo tab,
Relation  rel,
Constraint constr,
bool  recurse,
bool  recursing,
bool  is_readd,
LOCKMODE  lockmode 
)
static

Definition at line 6562 of file tablecmds.c.

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

Referenced by ATExecAddConstraint().

6565 {
6566  List *newcons;
6567  ListCell *lcon;
6568  List *children;
6569  ListCell *child;
6571 
6572  /* At top level, permission check was done in ATPrepCmd, else do it */
6573  if (recursing)
6575 
6576  /*
6577  * Call AddRelationNewConstraints to do the work, making sure it works on
6578  * a copy of the Constraint so transformExpr can't modify the original. It
6579  * returns a list of cooked constraints.
6580  *
6581  * If the constraint ends up getting merged with a pre-existing one, it's
6582  * omitted from the returned list, which is what we want: we do not need
6583  * to do any validation work. That can only happen at child tables,
6584  * though, since we disallow merging at the top level.
6585  */
6586  newcons = AddRelationNewConstraints(rel, NIL,
6587  list_make1(copyObject(constr)),
6588  recursing | is_readd, /* allow_merge */
6589  !recursing, /* is_local */
6590  is_readd); /* is_internal */
6591 
6592  /* we don't expect more than one constraint here */
6593  Assert(list_length(newcons) <= 1);
6594 
6595  /* Add each to-be-validated constraint to Phase 3's queue */
6596  foreach(lcon, newcons)
6597  {
6598  CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
6599 
6600  if (!ccon->skip_validation)
6601  {
6602  NewConstraint *newcon;
6603 
6604  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
6605  newcon->name = ccon->name;
6606  newcon->contype = ccon->contype;
6607  newcon->qual = ccon->expr;
6608 
6609  tab->constraints = lappend(tab->constraints, newcon);
6610  }
6611 
6612  /* Save the actually assigned name if it was defaulted */
6613  if (constr->conname == NULL)
6614  constr->conname = ccon->name;
6615 
6616  ObjectAddressSet(address, ConstraintRelationId, ccon->conoid);
6617  }
6618 
6619  /* At this point we must have a locked-down name to use */
6620  Assert(constr->conname != NULL);
6621 
6622  /* Advance command counter in case same table is visited multiple times */
6624 
6625  /*
6626  * If the constraint got merged with an existing constraint, we're done.
6627  * We mustn't recurse to child tables in this case, because they've
6628  * already got the constraint, and visiting them again would lead to an
6629  * incorrect value for coninhcount.
6630  */
6631  if (newcons == NIL)
6632  return address;
6633 
6634  /*
6635  * If adding a NO INHERIT constraint, no need to find our children.
6636  */
6637  if (constr->is_no_inherit)
6638  return address;
6639 
6640  /*
6641  * Propagate to children as appropriate. Unlike most other ALTER
6642  * routines, we have to do this one level of recursion at a time; we can't
6643  * use find_all_inheritors to do it in one pass.
6644  */
6645  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
6646 
6647  /*
6648  * Check if ONLY was specified with ALTER TABLE. If so, allow the
6649  * constraint creation only if there are no children currently. Error out
6650  * otherwise.
6651  */
6652  if (!recurse && children != NIL)
6653  ereport(ERROR,
6654  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6655  errmsg("constraint must be added to child tables too")));
6656 
6657  foreach(child, children)
6658  {
6659  Oid childrelid = lfirst_oid(child);
6660  Relation childrel;
6661  AlteredTableInfo *childtab;
6662 
6663  /* find_inheritance_children already got lock */
6664  childrel = heap_open(childrelid, NoLock);
6665  CheckTableNotInUse(childrel, "ALTER TABLE");
6666 
6667  /* Find or create work queue entry for this table */
6668  childtab = ATGetQueueEntry(wqueue, childrel);
6669 
6670  /* Recurse to child */
6671  ATAddCheckConstraint(wqueue, childtab, childrel,
6672  constr, recurse, true, is_readd, lockmode);
6673 
6674  heap_close(childrel, NoLock);
6675  }
6676 
6677  return address;
6678 }
#define NIL
Definition: pg_list.h:69
char * name
Definition: tablecmds.c:182
Node * qual
Definition: tablecmds.c:187
int errcode(int sqlerrcode)
Definition: elog.c:575
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:6562
#define heap_close(r, l)
Definition: heapam.h:97
char * conname
Definition: parsenodes.h:2028
unsigned int Oid
Definition: postgres_ext.h:31
#define ATT_TABLE
Definition: tablecmds.c:278
List * constraints
Definition: tablecmds.c:163
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
#define list_make1(x1)
Definition: pg_list.h:133
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:4565
bool skip_validation
Definition: heap.h:35
ConstrType contype
Definition: heap.h:30
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:2970
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
ConstrType contype
Definition: tablecmds.c:183
void * palloc0(Size size)
Definition: mcxt.c:878
void CommandCounterIncrement(void)
Definition: xact.c:922
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
bool is_no_inherit
Definition: parsenodes.h:2034
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:48
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
Oid conoid
Definition: heap.h:31
Node * expr
Definition: heap.h:34
static void ATSimplePermissions(Relation rel, int allowed_targets)
Definition: tablecmds.c:4602
#define ConstraintRelationId
Definition: pg_constraint.h:29
Definition: pg_list.h:45
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:283
char * name
Definition: heap.h:32
#define RelationGetRelid(relation)
Definition: rel.h:417
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal)
Definition: heap.c:2197
#define lfirst_oid(lc)
Definition: pg_list.h:108
static ObjectAddress ATAddForeignKeyConstraint ( AlteredTableInfo tab,
Relation  rel,
Constraint fkconstraint,
LOCKMODE  lockmode 
)
static

Definition at line 6689 of file tablecmds.c.

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

Referenced by ATExecAddConstraint().

6691 {
6692  Relation pkrel;
6693  int16 pkattnum[INDEX_MAX_KEYS];
6694  int16 fkattnum[INDEX_MAX_KEYS];
6695  Oid pktypoid[INDEX_MAX_KEYS];
6696  Oid fktypoid[INDEX_MAX_KEYS];
6697  Oid opclasses[INDEX_MAX_KEYS];
6698  Oid pfeqoperators[INDEX_MAX_KEYS];
6699  Oid ppeqoperators[INDEX_MAX_KEYS];
6700  Oid ffeqoperators[INDEX_MAX_KEYS];
6701  int i;
6702  int numfks,
6703  numpks;
6704  Oid indexOid;
6705  Oid constrOid;
6706  bool old_check_ok;
6707  ObjectAddress address;
6708  ListCell *old_pfeqop_item = list_head(fkconstraint->old_conpfeqop);
6709 
6710  /*
6711  * Grab ShareRowExclusiveLock on the pk table, so that someone doesn't
6712  * delete rows out from under us.
6713  */
6714  if (OidIsValid(fkconstraint->old_pktable_oid))
6715  pkrel = heap_open(fkconstraint->old_pktable_oid, ShareRowExclusiveLock);
6716  else
6717  pkrel = heap_openrv(fkconstraint->pktable, ShareRowExclusiveLock);
6718 
6719  /*
6720  * Validity checks (permission checks wait till we have the column
6721  * numbers)
6722  */
6723  if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6724  ereport(ERROR,
6725  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6726  errmsg("cannot reference partitioned table \"%s\"",
6727  RelationGetRelationName(pkrel))));
6728 
6729  if (pkrel->rd_rel->relkind != RELKIND_RELATION)
6730  ereport(ERROR,
6731  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
6732  errmsg("referenced relation \"%s\" is not a table",
6733  RelationGetRelationName(pkrel))));
6734 
6735  if (!allowSystemTableMods && IsSystemRelation(pkrel))
6736  ereport(ERROR,
6737  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
6738  errmsg("permission denied: \"%s\" is a system catalog",
6739  RelationGetRelationName(pkrel))));
6740 
6741  /*
6742  * References from permanent or unlogged tables to temp tables, and from
6743  * permanent tables to unlogged tables, are disallowed because the
6744  * referenced data can vanish out from under us. References from temp
6745  * tables to any other table type are also disallowed, because other
6746  * backends might need to run the RI triggers on the perm table, but they
6747  * can't reliably see tuples in the local buffers of other backends.
6748  */
6749  switch (rel->rd_rel->relpersistence)
6750  {
6752  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
6753  ereport(ERROR,
6754  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6755  errmsg("constraints on permanent tables may reference only permanent tables")));
6756  break;
6758  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT
6759  && pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
6760  ereport(ERROR,
6761  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6762  errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
6763  break;
6764  case RELPERSISTENCE_TEMP:
6765  if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
6766  ereport(ERROR,
6767  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6768  errmsg("constraints on temporary tables may reference only temporary tables")));
6769  if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
6770  ereport(ERROR,
6771  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6772  errmsg("constraints on temporary tables must involve temporary tables of this session")));
6773  break;
6774  }
6775 
6776  /*
6777  * Look up the referencing attributes to make sure they exist, and record
6778  * their attnums and type OIDs.
6779  */
6780  MemSet(pkattnum, 0, sizeof(pkattnum));
6781  MemSet(fkattnum, 0, sizeof(fkattnum));
6782  MemSet(pktypoid, 0, sizeof(pktypoid));
6783  MemSet(fktypoid, 0, sizeof(fktypoid));
6784  MemSet(opclasses, 0, sizeof(opclasses));
6785  MemSet(pfeqoperators, 0, sizeof(pfeqoperators));
6786  MemSet(ppeqoperators, 0, sizeof(ppeqoperators));
6787  MemSet(ffeqoperators, 0, sizeof(ffeqoperators));
6788 
6790  fkconstraint->fk_attrs,
6791  fkattnum, fktypoid);
6792 
6793  /*
6794  * If the attribute list for the referenced table was omitted, lookup the
6795  * definition of the primary key and use it. Otherwise, validate the
6796  * supplied attribute list. In either case, discover the index OID and
6797  * index opclasses, and the attnums and type OIDs of the attributes.
6798  */
6799  if (fkconstraint->pk_attrs == NIL)
6800  {
6801  numpks = transformFkeyGetPrimaryKey(pkrel, &indexOid,
6802  &fkconstraint->pk_attrs,
6803  pkattnum, pktypoid,
6804  opclasses);
6805  }
6806  else
6807  {
6808  numpks = transformColumnNameList(RelationGetRelid(pkrel),
6809  fkconstraint->pk_attrs,
6810  pkattnum, pktypoid);
6811  /* Look for an index matching the column list */
6812  indexOid = transformFkeyCheckAttrs(pkrel, numpks, pkattnum,
6813  opclasses);
6814  }
6815 
6816  /*
6817  * Now we can check permissions.
6818  */
6819  checkFkeyPermissions(pkrel, pkattnum, numpks);
6820  checkFkeyPermissions(rel, fkattnum, numfks);
6821 
6822  /*
6823  * Look up the equality operators to use in the constraint.
6824  *
6825  * Note that we have to be careful about the difference between the actual
6826  * PK column type and the opclass' declared input type, which might be
6827  * only binary-compatible with it. The declared opcintype is the right
6828  * thing to probe pg_amop with.
6829  */
6830  if (numfks != numpks)
6831  ereport(ERROR,
6832  (errcode(ERRCODE_INVALID_FOREIGN_KEY),
6833  errmsg("number of referencing and referenced columns for foreign key disagree")));
6834 
6835  /*
6836  * On the strength of a previous constraint, we might avoid scanning
6837  * tables to validate this one. See below.
6838  */
6839  old_check_ok = (fkconstraint->old_conpfeqop != NIL);
6840  Assert(!old_check_ok || numfks == list_length(fkconstraint->old_conpfeqop));
6841 
6842  for (i = 0; i < numpks; i++)
6843  {
6844  Oid pktype = pktypoid[i];
6845  Oid fktype = fktypoid[i];
6846  Oid fktyped;
6847  HeapTuple cla_ht;
6848  Form_pg_opclass cla_tup;
6849  Oid amid;
6850  Oid opfamily;
6851  Oid opcintype;
6852  Oid pfeqop;
6853  Oid ppeqop;
6854  Oid ffeqop;
6855  int16 eqstrategy;
6856  Oid pfeqop_right;
6857 
6858  /* We need several fields out of the pg_opclass entry */
6859  cla_ht = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclasses[i]));
6860  if (!HeapTupleIsValid(cla_ht))
6861  elog(ERROR, "cache lookup failed for opclass %u", opclasses[i]);
6862  cla_tup = (Form_pg_opclass) GETSTRUCT(cla_ht);
6863  amid = cla_tup->opcmethod;
6864  opfamily = cla_tup->opcfamily;
6865  opcintype = cla_tup->opcintype;
6866  ReleaseSysCache(cla_ht);
6867 
6868  /*
6869  * Check it's a btree; currently this can never fail since no other
6870  * index AMs support unique indexes. If we ever did have other types
6871  * of unique indexes, we'd need a way to determine which operator
6872  * strategy number is equality. (Is it reasonable to insist that
6873  * every such index AM use btree's number for equality?)
6874  */
6875  if (amid != BTREE_AM_OID)
6876  elog(ERROR, "only b-tree indexes are supported for foreign keys");
6877  eqstrategy = BTEqualStrategyNumber;
6878 
6879  /*
6880  * There had better be a primary equality operator for the index.
6881  * We'll use it for PK = PK comparisons.
6882  */
6883  ppeqop = get_opfamily_member(opfamily, opcintype, opcintype,
6884  eqstrategy);
6885 
6886  if (!OidIsValid(ppeqop))
6887  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
6888  eqstrategy, opcintype, opcintype, opfamily);
6889 
6890  /*
6891  * Are there equality operators that take exactly the FK type? Assume
6892  * we should look through any domain here.
6893  */
6894  fktyped = getBaseType(fktype);
6895 
6896  pfeqop = get_opfamily_member(opfamily, opcintype, fktyped,
6897  eqstrategy);
6898  if (OidIsValid(pfeqop))
6899  {
6900  pfeqop_right = fktyped;
6901  ffeqop = get_opfamily_member(opfamily, fktyped, fktyped,
6902  eqstrategy);
6903  }
6904  else
6905  {
6906  /* keep compiler quiet */
6907  pfeqop_right = InvalidOid;
6908  ffeqop = InvalidOid;
6909  }
6910 
6911  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
6912  {
6913  /*
6914  * Otherwise, look for an implicit cast from the FK type to the
6915  * opcintype, and if found, use the primary equality operator.
6916  * This is a bit tricky because opcintype might be a polymorphic
6917  * type such as ANYARRAY or ANYENUM; so what we have to test is
6918  * whether the two actual column types can be concurrently cast to
6919  * that type. (Otherwise, we'd fail to reject combinations such
6920  * as int[] and point[].)
6921  */
6922  Oid input_typeids[2];
6923  Oid target_typeids[2];
6924 
6925  input_typeids[0] = pktype;
6926  input_typeids[1] = fktype;
6927  target_typeids[0] = opcintype;
6928  target_typeids[1] = opcintype;
6929  if (can_coerce_type(2, input_typeids, target_typeids,
6931  {
6932  pfeqop = ffeqop = ppeqop;
6933  pfeqop_right = opcintype;
6934  }
6935  }
6936 
6937  if (!(OidIsValid(pfeqop) && OidIsValid(ffeqop)))
6938  ereport(ERROR,
6939  (errcode(ERRCODE_DATATYPE_MISMATCH),
6940  errmsg("foreign key constraint \"%s\" "
6941  "cannot be implemented",
6942  fkconstraint->conname),
6943  errdetail("Key columns \"%s\" and \"%s\" "
6944  "are of incompatible types: %s and %s.",
6945  strVal(list_nth(fkconstraint->fk_attrs, i)),
6946  strVal(list_nth(fkconstraint->pk_attrs, i)),
6947  format_type_be(fktype),
6948  format_type_be(pktype))));
6949 
6950  if (old_check_ok)
6951  {
6952  /*
6953  * When a pfeqop changes, revalidate the constraint. We could
6954  * permit intra-opfamily changes, but that adds subtle complexity
6955  * without any concrete benefit for core types. We need not
6956  * assess ppeqop or ffeqop, which RI_Initial_Check() does not use.
6957  */
6958  old_check_ok = (pfeqop == lfirst_oid(old_pfeqop_item));
6959  old_pfeqop_item = lnext(old_pfeqop_item);
6960  }
6961  if (old_check_ok)
6962  {
6963  Oid old_fktype;
6964  Oid new_fktype;
6965  CoercionPathType old_pathtype;
6966  CoercionPathType new_pathtype;
6967  Oid old_castfunc;
6968  Oid new_castfunc;
6969 
6970  /*
6971  * Identify coercion pathways from each of the old and new FK-side
6972  * column types to the right (foreign) operand type of the pfeqop.
6973  * We may assume that pg_constraint.conkey is not changing.
6974  */
6975  old_fktype = tab->oldDesc->attrs[fkattnum[i] - 1]->atttypid;
6976  new_fktype = fktype;
6977  old_pathtype = findFkeyCast(pfeqop_right, old_fktype,
6978  &old_castfunc);
6979  new_pathtype = findFkeyCast(pfeqop_right, new_fktype,
6980  &new_castfunc);
6981 
6982  /*
6983  * Upon a change to the cast from the FK column to its pfeqop
6984  * operand, revalidate the constraint. For this evaluation, a
6985  * binary coercion cast is equivalent to no cast at all. While
6986  * type implementors should design implicit casts with an eye
6987  * toward consistency of operations like equality, we cannot
6988  * assume here that they have done so.
6989  *
6990  * A function with a polymorphic argument could change behavior
6991  * arbitrarily in response to get_fn_expr_argtype(). Therefore,
6992  * when the cast destination is polymorphic, we only avoid
6993  * revalidation if the input type has not changed at all. Given
6994  * just the core data types and operator classes, this requirement
6995  * prevents no would-be optimizations.
6996  *
6997  * If the cast converts from a base type to a domain thereon, then
6998  * that domain type must be the opcintype of the unique index.
6999  * Necessarily, the primary key column must then be of the domain
7000  * type. Since the constraint was previously valid, all values on
7001  * the foreign side necessarily exist on the primary side and in
7002  * turn conform to the domain. Consequently, we need not treat
7003  * domains specially here.
7004  *
7005  * Since we require that all collations share the same notion of
7006  * equality (which they do, because texteq reduces to bitwise
7007  * equality), we don't compare collation here.
7008  *
7009  * We need not directly consider the PK type. It's necessarily
7010  * binary coercible to the opcintype of the unique index column,
7011  * and ri_triggers.c will only deal with PK datums in terms of
7012  * that opcintype. Changing the opcintype also changes pfeqop.
7013  */
7014  old_check_ok = (new_pathtype == old_pathtype &&
7015  new_castfunc == old_castfunc &&
7016  (!IsPolymorphicType(pfeqop_right) ||
7017  new_fktype == old_fktype));
7018 
7019  }
7020 
7021  pfeqoperators[i] = pfeqop;
7022  ppeqoperators[i] = ppeqop;
7023  ffeqoperators[i] = ffeqop;
7024  }
7025 
7026  /*
7027  * Record the FK constraint in pg_constraint.
7028  */
7029  constrOid = CreateConstraintEntry(fkconstraint->conname,
7030  RelationGetNamespace(rel),
7032  fkconstraint->deferrable,
7033  fkconstraint->initdeferred,
7034  fkconstraint->initially_valid,
7035  RelationGetRelid(rel),
7036  fkattnum,
7037  numfks,
7038  InvalidOid, /* not a domain
7039  * constraint */
7040  indexOid,
7041  RelationGetRelid(pkrel),
7042  pkattnum,
7043  pfeqoperators,
7044  ppeqoperators,
7045  ffeqoperators,
7046  numpks,
7047  fkconstraint->fk_upd_action,
7048  fkconstraint->fk_del_action,
7049  fkconstraint->fk_matchtype,
7050  NULL, /* no exclusion constraint */
7051  NULL, /* no check constraint */
7052  NULL,
7053  NULL,
7054  true, /* islocal */
7055  0, /* inhcount */
7056  true, /* isnoinherit */
7057  false); /* is_internal */
7058  ObjectAddressSet(address, ConstraintRelationId, constrOid);
7059 
7060  /*
7061  * Create the triggers that will enforce the constraint.
7062  */
7063  createForeignKeyTriggers(rel, RelationGetRelid(pkrel), fkconstraint,
7064  constrOid, indexOid);
7065 
7066  /*
7067  * Tell Phase 3 to check that the constraint is satisfied by existing
7068  * rows. We can skip this during table creation, when requested explicitly
7069  * by specifying NOT VALID in an ADD FOREIGN KEY command, and when we're
7070  * recreating a constraint following a SET DATA TYPE operation that did
7071  * not impugn its validity.
7072  */
7073  if (!old_check_ok && !fkconstraint->skip_validation)
7074  {
7075  NewConstraint *newcon;
7076 
7077  newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
7078  newcon->name = fkconstraint->conname;
7079  newcon->contype = CONSTR_FOREIGN;
7080  newcon->refrelid = RelationGetRelid(pkrel);
7081  newcon->refindid = indexOid;
7082  newcon->conid = constrOid;
7083  newcon->qual = (Node *) fkconstraint;
7084 
7085  tab->constraints = lappend(tab->constraints, newcon);
7086  }
7087 
7088  /*
7089  * Close pk table, but keep lock until we've committed.
7090  */
7091  heap_close(pkrel, NoLock);
7092 
7093  return address;
7094 }
signed short int16
Definition: c.h:255
#define NIL
Definition: pg_list.h:69
#define CONSTRAINT_FOREIGN
char * name
Definition: tablecmds.c:182
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
List * old_conpfeqop
Definition: parsenodes.h:2059
bool IsSystemRelation(Relation relation)
Definition: catalog.c:62
#define RELPERSISTENCE_UNLOGGED
Definition: pg_class.h:171
char fk_matchtype
Definition: parsenodes.h:2056
static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids)
Definition: tablecmds.c:7443
#define BTREE_AM_OID
Definition: pg_am.h:70
bool rd_islocaltemp
Definition: rel.h:90
Form_pg_attribute * attrs
Definition: tupdesc.h:74
Node * qual
Definition: tablecmds.c:187
Definition: nodes.h:504
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
bool initdeferred
Definition: parsenodes.h:2030
#define MemSet(start, val, len)
Definition: c.h:857
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
#define heap_close(r, l)
Definition: heapam.h:97
List * pk_attrs
Definition: parsenodes.h:2055
char * conname
Definition: parsenodes.h:2028
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
static void checkFkeyPermissions(Relation rel, int16 *attnums, int natts)
Definition: tablecmds.c:7750
#define OidIsValid(objectId)
Definition: c.h:538
CoercionPathType
Definition: parse_coerce.h:24
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:152
List * constraints
Definition: tablecmds.c:163
#define RELPERSISTENCE_PERMANENT
Definition: pg_class.h:170
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define IsPolymorphicType(typid)
Definition: pg_type.h:741
bool deferrable
Definition: parsenodes.h:2029
TupleDesc oldDesc
Definition: tablecmds.c:159
void * list_nth(const List *list, int n)
Definition: list.c:410
#define NoLock
Definition: lockdefs.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:873
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
#define RelationGetRelationName(relation)
Definition: rel.h:437
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
static void createForeignKeyTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, Oid constraintOid, Oid indexOid)
Definition: tablecmds.c:7993
#define lnext(lc)
Definition: pg_list.h:105
#define ereport(elevel, rest)
Definition: elog.h:122
Oid old_pktable_oid
Definition: parsenodes.h:2060
List * lappend(List *list, void *datum)
Definition: list.c:128
ConstrType contype
Definition: tablecmds.c:183
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
void * palloc0(Size size)
Definition: mcxt.c:878
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1315
bool allowSystemTableMods
Definition: globals.c:111
#define InvalidOid
Definition: postgres_ext.h:36
bool initially_valid
Definition: parsenodes.h:2064
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, List **attnamelist, int16 *attnums, Oid *atttypids, Oid *opclasses)
Definition: tablecmds.c:7488
char fk_del_action
Definition: parsenodes.h:2058
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define ShareRowExclusiveLock
Definition: lockdefs.h:42
static CoercionPathType findFkeyCast(Oid targetTypeId, Oid sourceTypeId, Oid *funcid)
Definition: tablecmds.c:7726
#define INDEX_MAX_KEYS
static int list_length(const List *l)
Definition: pg_list.h:89
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
static Oid transformFkeyCheckAttrs(Relation pkrel, int numattrs, int16 *attnums, Oid *opclasses)
Definition: tablecmds.c:7585
bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, CoercionContext ccontext)
Definition: parse_coerce.c:527
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:219
#define RELPERSISTENCE_TEMP
Definition: pg_class.h:172
RangeVar * pktable
Definition: parsenodes.h:2053
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2239
#define RELKIND_RELATION
Definition: pg_class.h:160
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
bool skip_validation
Definition: parsenodes.h:2063
#define RelationGetRelid(relation)
Definition: rel.h:417
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid relId, const int16 *constraintKey, int constraintNKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, const char *conSrc, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:49
List * fk_attrs
Definition: parsenodes.h:2054
#define BTEqualStrategyNumber
Definition: stratnum.h:31
char fk_upd_action
Definition: parsenodes.h:2057
#define lfirst_oid(lc)
Definition: pg_list.h:108
#define RelationGetNamespace(relation)
Definition: rel.h:444
static bool ATColumnChangeRequiresRewrite ( Node expr,
AttrNumber  varattno 
)
static

Definition at line 8598 of file tablecmds.c.

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

Referenced by ATPrepAlterColumnType().

8599 {
8600  Assert(expr != NULL);
8601 
8602  for (;;)
8603  {
8604  /* only one varno, so no need to check that */
8605  if (IsA(expr, Var) &&((Var *) expr)->varattno == varattno)
8606  return false;
8607  else if (IsA(expr, RelabelType))
8608  expr = (Node *) ((RelabelType *) expr)->arg;
8609  else if (IsA(expr, CoerceToDomain))
8610  {
8611  CoerceToDomain *d = (CoerceToDomain *) expr;
8612 
8614  return true;
8615  expr = (Node *) d->arg;
8616  }
8617  else
8618  return true;
8619  }
8620 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:555
Definition: nodes.h:504
Definition: primnodes.h:163
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1059
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
void * arg
static void ATController ( AlterTableStmt parsetree,
Relation  rel,
List cmds,
bool  recurse,
LOCKMODE  lockmode 
)
static

Definition at line 3364 of file tablecmds.c.

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

Referenced by AlterTable(), and AlterTableInternal().

3366 {
3367  List *wqueue = NIL;
3368  ListCell *lcmd;
3369 
3370  /* Phase 1: preliminary examination of commands, create work queue */
3371  foreach(lcmd, cmds)
3372  {
3373  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
3374 
3375  ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode);
3376  }
3377 
3378  /* Close the relation, but keep lock until commit */
3379  relation_close(rel, NoLock);
3380 
3381  /* Phase 2: update system catalogs */
3382  ATRewriteCatalogs(&wqueue, lockmode);
3383 
3384  /* Phase 3: scan/rewrite tables as needed */
3385  ATRewriteTables(parsetree, &wqueue, lockmode);
3386 }
#define NIL
Definition: pg_list.h:69
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1263
#define NoLock
Definition: lockdefs.h:34
static void ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
Definition: tablecmds.c:4020
static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:3398
#define lfirst(lc)
Definition: pg_list.h:106
static void ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode)
Definition: tablecmds.c:3686
Definition: pg_list.h:45
void AtEOSubXact_on_commit_actions ( bool  isCommit,
SubTransactionId  mySubid,
SubTransactionId  parentSubid 
)

Definition at line 12556 of file tablecmds.c.

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

Referenced by AbortSubTransaction(), and CommitSubTransaction().

12558 {
12559  ListCell *cur_item;
12560  ListCell *prev_item;
12561 
12562  prev_item = NULL;
12563  cur_item = list_head(on_commits);
12564 
12565  while (cur_item != NULL)
12566  {
12567  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
12568 
12569  if (!isCommit && oc->creating_subid == mySubid)
12570  {
12571  /* cur_item must be removed */
12572  on_commits = list_delete_cell(on_commits, cur_item, prev_item);
12573  pfree(oc);
12574  if (prev_item)
12575  cur_item = lnext(prev_item);
12576  else
12577  cur_item = list_head(on_commits);
12578  }
12579  else
12580  {
12581  /* cur_item must be preserved */
12582  if (oc->creating_subid == mySubid)
12583  oc->creating_subid = parentSubid;
12584  if (oc->deleting_subid == mySubid)
12585  oc->deleting_subid = isCommit ? parentSubid : InvalidSubTransactionId;
12586  prev_item = cur_item;
12587  cur_item = lnext(prev_item);
12588  }
12589  }
12590 }
SubTransactionId creating_subid
Definition: tablecmds.c:120
void pfree(void *pointer)
Definition: mcxt.c:950
static List * on_commits
Definition: tablecmds.c:124
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
List * list_delete_cell(List *list, ListCell *cell, ListCell *prev)
Definition: list.c:528
SubTransactionId deleting_subid
Definition: tablecmds.c:121
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
#define InvalidSubTransactionId
Definition: c.h:403
void AtEOXact_on_commit_actions ( bool  isCommit)

Definition at line 12514 of file tablecmds.c.

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

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

12515 {
12516  ListCell *cur_item;
12517  ListCell *prev_item;
12518 
12519  prev_item = NULL;
12520  cur_item = list_head(on_commits);
12521 
12522  while (cur_item != NULL)
12523  {
12524  OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
12525 
12526  if (isCommit ? oc->deleting_subid != InvalidSubTransactionId :
12528  {
12529  /* cur_item must be removed */
12530  on_commits = list_delete_cell(on_commits, cur_item, prev_item);
12531  pfree(oc);
12532  if (prev_item)
12533  cur_item = lnext(prev_item);
12534  else
12535  cur_item = list_head(on_commits);
12536  }
12537  else
12538  {
12539  /* cur_item must be preserved */
12542  prev_item = cur_item;
12543  cur_item = lnext(prev_item);
12544  }
12545  }
12546 }
SubTransactionId creating_subid
Definition: tablecmds.c:120
void pfree(void *pointer)
Definition: mcxt.c:950
static List * on_commits
Definition: tablecmds.c:124
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
List * list_delete_cell(List *list, ListCell *cell, ListCell *prev)
Definition: list.c:528
SubTransactionId deleting_subid
Definition: tablecmds.c:121
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
#define InvalidSubTransactionId
Definition: c.h:403
static ObjectAddress ATExecAddColumn ( List **  wqueue,
AlteredTableInfo tab,
Relation  rel,
ColumnDef colDef,
bool  isOid,
bool  recurse,
bool  recursing,
bool  if_not_exists,
LOCKMODE  lockmode 
)
static

Definition at line 5022 of file tablecmds.c.

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

Referenced by ATExecCmd().

5026 {
5027  Oid myrelid = RelationGetRelid(rel);
5028  Relation pgclass,
5029  attrdesc;
5030  HeapTuple reltup;
5031  FormData_pg_attribute attribute;
5032  int newattnum;
5033  char relkind;
5034  HeapTuple typeTuple;
5035  Oid typeOid;
5036  int32 typmod;
5037  Oid collOid;
5038  Form_pg_type tform;
5039  Expr *defval;
5040  List *children;
5041  ListCell *child;
5042  AclResult aclresult;
5043  ObjectAddress address;
5044 
5045  /* At top level, permission check was done in ATPrepCmd, else do it */
5046  if (recursing)
5048 
5049  if (rel->rd_rel->relispartition && !recursing)
5050  ereport(ERROR,
5051  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5052  errmsg("cannot add column to a partition")));
5053 
5055 
5056  /*
5057  * Are we adding the column to a recursion child? If so, check whether to
5058  * merge with an existing definition for the column. If we do merge, we
5059  * must not recurse. Children will already have the column, and recursing
5060  * into them would mess up attinhcount.
5061  */
5062  if (colDef->inhcount > 0)
5063  {
5064  HeapTuple tuple;
5065 
5066  /* Does child already have a column by this name? */
5067  tuple = SearchSysCacheCopyAttName(myrelid, colDef->colname);
5068  if (HeapTupleIsValid(tuple))
5069  {
5070  Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
5071  Oid ctypeId;
5072  int32 ctypmod;
5073  Oid ccollid;
5074 
5075  /* Child column must match on type, typmod, and collation */
5076  typenameTypeIdAndMod(NULL, colDef->typeName, &ctypeId, &ctypmod);
5077  if (ctypeId != childatt->atttypid ||
5078  ctypmod != childatt->atttypmod)
5079  ereport(ERROR,
5080  (errcode(ERRCODE_DATATYPE_MISMATCH),
5081  errmsg("child table \"%s\" has different type for column \"%s\"",
5082  RelationGetRelationName(rel), colDef->colname)));
5083  ccollid = GetColumnDefCollation(NULL, colDef, ctypeId);
5084  if (ccollid != childatt->attcollation)
5085  ereport(ERROR,
5086  (errcode(ERRCODE_COLLATION_MISMATCH),
5087  errmsg("child table \"%s\" has different collation for column \"%s\"",
5088  RelationGetRelationName(rel), colDef->colname),
5089  errdetail("\"%s\" versus \"%s\"",
5090  get_collation_name(ccollid),
5091  get_collation_name(childatt->attcollation))));
5092 
5093  /* If it's OID, child column must actually be OID */
5094  if (isOid && childatt->attnum != ObjectIdAttributeNumber)
5095  ereport(ERROR,
5096  (errcode(ERRCODE_DATATYPE_MISMATCH),
5097  errmsg("child table \"%s\" has a conflicting \"%s\" column",
5098  RelationGetRelationName(rel), colDef->colname)));
5099 
5100  /* Bump the existing child att's inhcount */
5101  childatt->attinhcount++;
5102  CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
5103 
5104  heap_freetuple(tuple);
5105 
5106  /* Inform the user about the merge */
5107  ereport(NOTICE,
5108  (errmsg("merging definition of column \"%s\" for child \"%s\"",
5109  colDef->colname, RelationGetRelationName(rel))));
5110 
5111  heap_close(attrdesc, RowExclusiveLock);
5112  return InvalidObjectAddress;
5113  }
5114  }
5115 
5117 
5118  reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
5119  if (!HeapTupleIsValid(reltup))
5120  elog(ERROR, "cache lookup failed for relation %u", myrelid);
5121  relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
5122 
5123  /* skip if the name already exists and if_not_exists is true */
5124  if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
5125  {
5126  heap_close(attrdesc, RowExclusiveLock);
5127  heap_freetuple(reltup);
5128  heap_close(pgclass, RowExclusiveLock);
5129  return InvalidObjectAddress;
5130  }
5131 
5132  /* Determine the new attribute's number */
5133  if (isOid)
5134  newattnum = ObjectIdAttributeNumber;
5135  else
5136  {
5137  newattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts + 1;
5138  if (newattnum > MaxHeapAttributeNumber)
5139  ereport(ERROR,
5140  (errcode(ERRCODE_TOO_MANY_COLUMNS),
5141  errmsg("tables can have at most %d columns",
5143  }
5144 
5145  typeTuple = typenameType(NULL, colDef->typeName, &typmod);
5146  tform = (Form_pg_type) GETSTRUCT(typeTuple);
5147  typeOid = HeapTupleGetOid(typeTuple);
5148 
5149  aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
5150  if (aclresult != ACLCHECK_OK)
5151  aclcheck_error_type(aclresult, typeOid);
5152 
5153  collOid = GetColumnDefCollation(NULL, colDef, typeOid);
5154 
5155  /* make sure datatype is legal for a column */
5156  CheckAttributeType(colDef->colname, typeOid, collOid,
5157  list_make1_oid(rel->rd_rel->reltype),
5158  false);
5159 
5160  /* construct new attribute's pg_attribute entry */
5161  attribute.attrelid = myrelid;
5162  namestrcpy(&(attribute.attname), colDef->colname);
5163  attribute.atttypid = typeOid;
5164  attribute.attstattarget = (newattnum > 0) ? -1 : 0;
5165  attribute.attlen = tform->typlen;
5166  attribute.attcacheoff = -1;
5167  attribute.atttypmod = typmod;
5168  attribute.attnum = newattnum;
5169  attribute.attbyval = tform->typbyval;
5170  attribute.attndims = list_length(colDef->typeName->arrayBounds);
5171  attribute.attstorage = tform->typstorage;
5172  attribute.attalign = tform->typalign;
5173  attribute.attnotnull = colDef->is_not_null;
5174  attribute.atthasdef = false;
5175  attribute.attisdropped = false;
5176  attribute.attislocal = colDef->is_local;
5177  attribute.attinhcount = colDef->inhcount;
5178  attribute.attcollation = collOid;
5179  /* attribute.attacl is handled by InsertPgAttributeTuple */
5180 
5181  ReleaseSysCache(typeTuple);
5182 
5183  InsertPgAttributeTuple(attrdesc, &attribute, NULL);
5184 
5185  heap_close(attrdesc, RowExclusiveLock);
5186 
5187  /*
5188  * Update pg_class tuple as appropriate
5189  */
5190  if (isOid)
5191  ((Form_pg_class) GETSTRUCT(reltup))->relhasoids = true;
5192  else
5193  ((Form_pg_class) GETSTRUCT(reltup))->relnatts = newattnum;
5194 
5195  CatalogTupleUpdate(pgclass, &reltup->t_self, reltup);
5196 
5197  heap_freetuple(reltup);
5198 
5199  /* Post creation hook for new attribute */
5200  InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
5201 
5202  heap_close(pgclass, RowExclusiveLock);
5203 
5204  /* Make the attribute's catalog entry visible */
5206 
5207  /*
5208  * Store the DEFAULT, if any, in the catalogs
5209  */
5210  if (colDef->raw_default)
5211  {
5212  RawColumnDefault *rawEnt;
5213 
5214  rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
5215  rawEnt->attnum = attribute.attnum;
5216  rawEnt->raw_default = copyObject(colDef->raw_default);
5217 
5218  /*
5219  * This function is intended for CREATE TABLE, so it processes a
5220  * _list_ of defaults, but we just do one.
5221  */
5223  false, true, false);
5224 
5225  /* Make the additional catalog changes visible */
5227  }
5228 
5229  /*
5230  * Tell Phase 3 to fill in the default expression, if there is one.
5231  *
5232  * If there is no default, Phase 3 doesn't have to do anything, because
5233  * that effectively means that the default is NULL. The heap tuple access
5234  * routines always check for attnum > # of attributes in tuple, and return
5235  * NULL if so, so without any modification of the tuple data we will get
5236  * the effect of NULL values in the new column.
5237  *
5238  * An exception occurs when the new column is of a domain type: the domain
5239  * might have a NOT NULL constraint, or a check constraint that indirectly
5240  * rejects nulls. If there are any domain constraints then we construct
5241  * an explicit NULL default value that will be passed through
5242  * CoerceToDomain processing. (This is a tad inefficient, since it causes
5243  * rewriting the table which we really don't have to do, but the present
5244  * design of domain processing doesn't offer any simple way of checking
5245  * the constraints more directly.)
5246  *
5247  * Note: we use build_column_default, and not just the cooked default
5248  * returned by AddRelationNewConstraints, so that the right thing happens
5249  * when a datatype's default applies.
5250  *
5251  * We skip this step completely for views and foreign tables. For a view,
5252  * we can only get here from CREATE OR REPLACE VIEW, which historically
5253  * doesn't set up defaults, not even for domain-typed columns. And in any
5254  * case we mustn't invoke Phase 3 on a view or foreign table, since they
5255  * have no storage.
5256  */
5257  if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE
5258  && relkind != RELKIND_FOREIGN_TABLE && attribute.attnum > 0)
5259  {
5260  defval = (Expr *) build_column_default(rel, attribute.attnum);
5261 
5262  if (!defval && DomainHasConstraints(typeOid))
5263  {
5264  Oid baseTypeId;
5265  int32 baseTypeMod;
5266  Oid baseTypeColl;
5267 
5268  baseTypeMod = typmod;
5269  baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
5270  baseTypeColl = get_typcollation(baseTypeId);
5271  defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod, baseTypeColl);
5272  defval = (Expr *) coerce_to_target_type(NULL,
5273  (Node *) defval,
5274  baseTypeId,
5275  typeOid,
5276  typmod,
5279  -1);
5280  if (defval == NULL) /* should not happen */
5281  elog(ERROR, "failed to coerce base type to domain");
5282  }
5283 
5284  if (defval)
5285  {
5287 
5288  newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
5289  newval->attnum = attribute.attnum;
5290  newval->expr = expression_planner(defval);
5291 
5292  tab->newvals = lappend(tab->newvals, newval);
5294  }
5295 
5296  /*
5297  * If the new column is NOT NULL, tell Phase 3 it needs to test that.
5298  * (Note we don't do this for an OID column. OID will be marked not
5299  * null, but since it's filled specially, there's no need to test
5300  * anything.)
5301  */
5302  tab->new_notnull |= colDef->is_not_null;
5303  }
5304 
5305  /*
5306  * If we are adding an OID column, we have to tell Phase 3 to rewrite the
5307  * table to fix that.
5308  */
5309  if (isOid)
5310  tab->rewrite |= AT_REWRITE_ALTER_OID;
5311 
5312  /*
5313  * Add needed dependency entries for the new column.
5314  */
5315  add_column_datatype_dependency(myrelid, newattnum, attribute.atttypid);
5316  add_column_collation_dependency(myrelid, newattnum, attribute.attcollation);
5317 
5318  /*
5319  * Propagate to children as appropriate. Unlike most other ALTER
5320  * routines, we have to do this one level of recursion at a time; we can't
5321  * use find_all_inheritors to do it in one pass.
5322  */
5323  children = find_inheritance_children(RelationGetRelid(rel), lockmode);
5324 
5325  /*
5326  * If we are told not to recurse, there had better not be any child
5327  * tables; else the addition would put them out of step.
5328  */
5329  if (children && !recurse)
5330  ereport(ERROR,
5331  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
5332  errmsg("column must be added to child tables too")));
5333 
5334  /* Children should see column as singly inherited */
5335  if (!recursing)
5336  {
5337  colDef = copyObject(colDef);
5338  colDef->inhcount = 1;
5339  colDef->is_local = false;
5340  }
5341 
5342  foreach(child, children)
5343  {
5344  Oid childrelid = lfirst_oid(child);
5345  Relation childrel;
5346  AlteredTableInfo *childtab;
5347 
5348  /* find_inheritance_children already got lock */
5349  childrel = heap_open(childrelid, NoLock);
5350  CheckTableNotInUse(childrel, "ALTER TABLE");
5351 
5352  /* Find or create work queue entry for this table */
5353  childtab = ATGetQueueEntry(wqueue, childrel);
5354 
5355  /* Recurse to child; return value is ignored */
5356  ATExecAddColumn(wqueue, childtab, childrel,
5357  colDef, isOid, recurse, true,
5358  if_not_exists, lockmode);
5359 
5360  heap_close(childrel, NoLock);
5361  }
5362 
5363  ObjectAddressSubSet(address, RelationRelationId, myrelid, newattnum);
5364  return address;
5365 }
#define NIL
Definition: pg_list.h:69
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
Definition: lsyscache.c:2256
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:247
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
AttrNumber attnum
Definition: heap.h:24
bool is_local
Definition: parsenodes.h:634
Oid GetUserId(void)
Definition: miscinit.c:283
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
char * get_collation_name(Oid colloid)
Definition: lsyscache.c:935
#define RelationRelationId
Definition: pg_class.h:29
Expr * expression_planner(Expr *expr)
Definition: planner.c:5382
static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, ColumnDef *colDef, bool isOid, bool recurse, bool recursing, bool if_not_exists, LOCKMODE lockmode)
Definition: tablecmds.c:5022
Definition: nodes.h:504
#define AttributeRelationId
Definition: pg_attribute.h:33
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
bool is_not_null
Definition: parsenodes.h:635
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
unsigned int Oid
Definition: postgres_ext.h:31
#define ATT_TABLE
Definition: tablecmds.c:278
int namestrcpy(Name name, const char *str)
Definition: name.c:217
#define RELKIND_COMPOSITE_TYPE
Definition: pg_class.h:166
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3440
signed int int32
Definition: c.h:256
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:334
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1059
#define list_make1(x1)
Definition: pg_list.h:133
#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:5425
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:77
HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname)
Definition: syscache.c:1227
ItemPointerData t_self
Definition: htup.h:65
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid)
Definition: tablecmds.c:5443
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define RelationGetRelationName(relation)
Definition: rel.h:437
static AlteredTableInfo * ATGetQueueEntry(List **wqueue, Relation rel)
Definition: tablecmds.c:4565
Node * raw_default
Definition: heap.h:25
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:184
#define ACL_USAGE
Definition: parsenodes.h:73
#define AT_REWRITE_ALTER_OID
Definition: event_trigger.h:34
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:2970
#define ereport(elevel, rest)
Definition: elog.h:122
Node * raw_default
Definition: parsenodes.h:638
List * lappend(List *list, void *datum)
Definition: list.c:128
void CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation, List *containing_rowtypes, bool allow_system_table_mods)
Definition: heap.c:487
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:878
AclResult
Definition: acl.h:170
void CommandCounterIncrement(void)
Definition: xact.c:922
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
#define list_make1_oid(x1)
Definition: pg_list.h:145
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
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:168
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:48
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:2749
#define NOTICE
Definition: elog.h:37
#define MaxHeapAttributeNumber
Definition: htup_details.h:47
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
static int list_length(const List *l)
Definition: pg_list.h:89
#define newval
TypeName * typeName
Definition: parsenodes.h:632
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:161
List * arrayBounds
Definition: parsenodes.h:206
void InsertPgAttributeTuple(Relation pg_attribute_rel, Form_pg_attribute new_attribute, CatalogIndexState indstate)
Definition: heap.c:597
const ObjectAddress InvalidObjectAddress
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
static bool check_for_column_name_collision(Relation rel, const char *colname, bool if_not_exists)
Definition: tablecmds.c:5372
#define RELKIND_VIEW
Definition: pg_class.h:164
int inhcount
Definition: parsenodes.h:633
static void ATSimplePermissions(Relation rel, int allowed_targets)
Definition: tablecmds.c:4602
char * colname
Definition: parsenodes.h:631
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4517
Definition: pg_list.h:45
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:283
#define RelationGetRelid(relation)
Definition: rel.h:417
List * AddRelationNewConstraints(Relation rel, List *newColDefaults, List *newConstraints, bool allow_merge, bool is_local, bool is_internal)
Definition: heap.c:2197
#define lfirst_oid(lc)
Definition: pg_list.h:108
AttrNumber attnum
Definition: tablecmds.c:200
static ObjectAddress ATExecAddConstraint ( List **  wqueue,
AlteredTableInfo tab,
Relation  rel,
Constraint newConstraint,
bool  recurse,
bool  is_readd,
LOCKMODE  lockmode 
)
static

Definition at line 6484 of file tablecmds.c.

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

Referenced by ATExecCmd().

6487 {
6489 
6490  Assert(IsA(newConstraint, Constraint));
6491 
6492  /*
6493  * Currently, we only expect to see CONSTR_CHECK and CONSTR_FOREIGN nodes
6494  * arriving here (see the preprocessing done in parse_utilcmd.c). Use a
6495  * switch anyway to make it easier to add more code later.
6496  */
6497  switch (newConstraint->contype)
6498  {
6499  case CONSTR_CHECK:
6500  address =
6501  ATAddCheckConstraint(wqueue, tab, rel,
6502  newConstraint, recurse, false, is_readd,
6503  lockmode);
6504  break;
6505 
6506  case CONSTR_FOREIGN:
6507 
6508  /*
6509  * Note that we currently never recurse for FK constraints, so the
6510  * "recurse" flag is silently ignored.
6511  *
6512  * Assign or validate constraint name
6513  */
6514  if (newConstraint->conname)
6515  {
6517  RelationGetRelid(rel),
6518  RelationGetNamespace(rel),
6519  newConstraint->conname))
6520  ereport(ERROR,
6522  errmsg("constraint \"%s\" for relation \"%s\" already exists",
6523  newConstraint->conname,
6524  RelationGetRelationName(rel))));
6525  }
6526  else
6527  newConstraint->conname =
6529  strVal(linitial(newConstraint->fk_attrs)),
6530  "fkey",
6531  RelationGetNamespace(rel),
6532  NIL);
6533 
6534  address = ATAddForeignKeyConstraint(tab, rel, newConstraint,
6535  lockmode);
6536  break;
6537 
6538  default:
6539  elog(ERROR, "unrecognized constraint type: %d",
6540  (int) newConstraint->contype);
6541  }
6542 
6543  return address;
6544 }
#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:555
static ObjectAddress ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint, LOCKMODE lockmode)
Definition: tablecmds.c:6689
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
static ObjectAddress ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, bool recurse, bool recursing, bool is_readd, LOCKMODE lockmode)
Definition: tablecmds.c:6562
char * conname
Definition: parsenodes.h:2028
#define linitial(l)
Definition: pg_list.h:110
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:437
#define ereport(elevel, rest)
Definition: elog.h:122
#define Assert(condition)
Definition: c.h:675
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, Oid objNamespace, const char *conname)
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
ConstrType contype
Definition: parsenodes.h:2025
#define elog
Definition: elog.h:219
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
#define RelationGetRelid(relation)
Definition: rel.h:417
List * fk_attrs
Definition: parsenodes.h:2054
#define RelationGetNamespace(relation)
Definition: rel.h:444
static ObjectAddress ATExecAddIndex ( AlteredTableInfo tab,
Relation  rel,
IndexStmt stmt,
bool  is_rebuild,
LOCKMODE  lockmode 
)
static

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

6355 {
6356  bool check_rights;
6357  bool skip_build;
6358  bool quiet;
6359  ObjectAddress address;
6360 
6361  Assert(IsA(stmt, IndexStmt));
6362  Assert(!stmt->concurrent);
6363 
6364  /* The IndexStmt has already been through transformIndexStmt */
6365  Assert(stmt->transformed);
6366 
6367  /* suppress schema rights check when rebuilding existing index */
6368  check_rights = !is_rebuild;
6369  /* skip index build if phase 3 will do it or we're reusing an old one */
6370  skip_build = tab->rewrite > 0 || OidIsValid(stmt->oldNode);
6371  /* suppress notices when rebuilding existing index */
6372  quiet = is_rebuild;
6373 
6374  address = DefineIndex(RelationGetRelid(rel),
6375  stmt,
6376  InvalidOid, /* no predefined OID */
6377  true, /* is_alter_table */
6378  check_rights,
6379  skip_build,
6380  quiet);
6381 
6382  /*
6383  * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
6384  * index instead of building from scratch. The DROP of the old edition of
6385  * this index will have scheduled the storage for deletion at commit, so
6386  * cancel that pending deletion.
6387  */
6388  if (OidIsValid(stmt->oldNode))
6389  {
6390  Relation irel = index_open(address.objectId, NoLock);
6391 
6392  RelationPreserveStorage(irel->rd_node, true);
6393  index_close(irel, NoLock);
6394  }
6395 
6396  return address;
6397 }
void RelationPreserveStorage(RelFileNode rnode, bool atCommit)
Definition: storage.c:190
#define IsA(nodeptr, _type_)
Definition: nodes.h:555
#define OidIsValid(objectId)
Definition: c.h:538
#define NoLock
Definition: lockdefs.h:34
bool transformed
Definition: parsenodes.h:2655
#define InvalidOid
Definition: postgres_ext.h:36
RelFileNode rd_node
Definition: rel.h:85
#define Assert(condition)
Definition: c.h:675
ObjectAddress DefineIndex(Oid relationId, IndexStmt *stmt, Oid indexRelationId, bool is_alter_table, bool check_rights, bool skip_build, bool quiet)
Definition: indexcmds.c:305
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
bool concurrent
Definition: parsenodes.h:2656
#define RelationGetRelid(relation)
Definition: rel.h:417
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
static ObjectAddress ATExecAddIndexConstraint ( AlteredTableInfo tab,
Relation  rel,
IndexStmt stmt,
LOCKMODE  lockmode 
)
static

Definition at line 6405 of file tablecmds.c.

References AccessShareLock, allowSystemTableMods, Assert, BuildIndexInfo(), CONSTRAINT_PRIMARY, CONSTRAINT_UNIQUE, IndexStmt::deferrable, elog, ereport, errmsg(), ERROR, IndexStmt::idxname, IndexInfo::ii_Unique, index_check_primary_key(), index_close(), index_constraint_create(), index_open(), IndexStmt::indexOid, IndexStmt::initdeferred, IsA, IndexStmt::isconstraint, NoLock, NOTICE, NULL, OidIsValid, IndexStmt::primary, pstrdup(), RelationGetRelationName, and RenameRelationInternal().

Referenced by ATExecCmd().

6407 {
6408  Oid index_oid = stmt->indexOid;
6409  Relation indexRel;
6410  char *indexName;
6411  IndexInfo *indexInfo;
6412  char *constraintName;
6413  char constraintType;
6414  ObjectAddress address;
6415 
6416  Assert(IsA(stmt, IndexStmt));
6417  Assert(OidIsValid(index_oid));
6418  Assert(stmt->isconstraint);
6419 
6420  indexRel = index_open(index_oid, AccessShareLock);
6421 
6422  indexName = pstrdup(RelationGetRelationName(indexRel));
6423 
6424  indexInfo = BuildIndexInfo(indexRel);
6425 
6426  /* this should have been checked at parse time */
6427  if (!indexInfo->ii_Unique)
6428  elog(ERROR, "index \"%s\" is not unique", indexName);
6429 
6430  /*
6431  * Determine name to assign to constraint. We require a constraint to
6432  * have the same name as the underlying index; therefore, use the index's
6433  * existing name as the default constraint name, and if the user
6434  * explicitly gives some other name for the constraint, rename the index
6435  * to match.
6436  */
6437  constraintName = stmt->idxname;
6438  if (constraintName == NULL)
6439  constraintName = indexName;
6440  else if (strcmp(constraintName, indexName) != 0)
6441  {
6442  ereport(NOTICE,
6443  (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
6444  indexName, constraintName)));
6445  RenameRelationInternal(index_oid, constraintName, false);
6446  }
6447 
6448  /* Extra checks needed if making primary key */
6449  if (stmt->primary)
6450  index_check_primary_key(rel, indexInfo, true);
6451 
6452  /* Note we currently don't support EXCLUSION constraints here */
6453  if (stmt->primary)
6454  constraintType = CONSTRAINT_PRIMARY;
6455  else
6456  constraintType = CONSTRAINT_UNIQUE;
6457 
6458  /* Create the catalog entries for the constraint */
6459  address = index_constraint_create(rel,
6460  index_oid,
6461  indexInfo,
6462  constraintName,
6463  constraintType,
6464  stmt->deferrable,
6465  stmt->initdeferred,
6466  stmt->primary,
6467  true, /* update pg_index */
6468  true, /* remove old dependencies */
6470  false); /* is_internal */
6471 
6472  index_close(indexRel, NoLock);
6473 
6474  return address;
6475 }
bool deferrable
Definition: parsenodes.h:2653
bool primary
Definition: parsenodes.h:2651
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
Definition: tablecmds.c:2874
#define IsA(nodeptr, _type_)
Definition: nodes.h:555
char * pstrdup(const char *in)
Definition: mcxt.c:1077
#define AccessShareLock
Definition: lockdefs.h:36
void index_check_primary_key(Relation heapRel, IndexInfo *indexInfo, bool is_alter_table)
Definition: index.c:192
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:1639
unsigned int Oid
Definition: postgres_ext.h:31
#define CONSTRAINT_UNIQUE
#define OidIsValid(objectId)
Definition: c.h:538
#define CONSTRAINT_PRIMARY
Oid indexOid
Definition: parsenodes.h:2648
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:437
#define ereport(elevel, rest)
Definition: elog.h:122
char * idxname
Definition: parsenodes.h:2639
bool allowSystemTableMods
Definition: globals.c:111
#define NOTICE
Definition: elog.h:37
bool ii_Unique
Definition: execnodes.h:145
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
bool initdeferred
Definition: parsenodes.h:2654
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
bool isconstraint
Definition: parsenodes.h:2652
int errmsg(const char *fmt,...)
Definition: elog.c:797
ObjectAddress index_constraint_create(Relation heapRelation, Oid indexRelationId, IndexInfo *indexInfo, const char *constraintName, char constraintType, bool deferrable, bool initdeferred, bool mark_as_primary, bool update_pgindex, bool remove_old_dependencies, bool allow_system_table_mods, bool is_internal)
Definition: index.c:1147
#define elog
Definition: elog.h:219
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
static ObjectAddress ATExecAddInherit ( Relation  child_rel,
RangeVar parent,
LOCKMODE  lockmode 
)
static

Definition at line 10599 of file tablecmds.c.

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

Referenced by ATExecCmd().

10600 {
10601  Relation parent_rel;
10602  List *children;
10603  ObjectAddress address;
10604 
10605  /*
10606  * A self-exclusive lock is needed here. See the similar case in
10607  * MergeAttributes() for a full explanation.
10608  */
10609  parent_rel = heap_openrv(parent, ShareUpdateExclusiveLock);
10610 
10611  /*
10612  * Must be owner of both parent and child -- child was checked by
10613  * ATSimplePermissions call in ATPrepCmd
10614  */
10616 
10617  /* Permanent rels cannot inherit from temporary ones */
10618  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
10619  child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
10620  ereport(ERROR,
10621  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10622  errmsg("cannot inherit from temporary relation \"%s\"",
10623  RelationGetRelationName(parent_rel))));
10624 
10625  /* If parent rel is temp, it must belong to this session */
10626  if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
10627  !parent_rel->rd_islocaltemp)
10628  ereport(ERROR,
10629  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10630  errmsg("cannot inherit from temporary relation of another session")));
10631 
10632  /* Ditto for the child */
10633  if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
10634  !child_rel->rd_islocaltemp)
10635  ereport(ERROR,
10636  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10637  errmsg("cannot inherit to temporary relation of another session")));
10638 
10639  /* Prevent partitioned tables from becoming inheritance parents */
10640  if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
10641  ereport(ERROR,
10642  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10643  errmsg("cannot inherit from partitioned table \"%s\"",
10644  parent->relname)));
10645 
10646  /* Likewise for partitions */
10647  if (parent_rel->rd_rel->relispartition)
10648  ereport(ERROR,
10649  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10650  errmsg("cannot inherit from a partition")));
10651 
10652  /*
10653  * Prevent circularity by seeing if proposed parent inherits from child.
10654  * (In particular, this disallows making a rel inherit from itself.)
10655  *
10656  * This is not completely bulletproof because of race conditions: in
10657  * multi-level inheritance trees, someone else could concurrently be
10658  * making another inheritance link that closes the loop but does not join
10659  * either of the rels we have locked. Preventing that seems to require
10660  * exclusive locks on the entire inheritance tree, which is a cure worse
10661  * than the disease. find_all_inheritors() will cope with circularity
10662  * anyway, so don't sweat it too much.
10663  *
10664  * We use weakest lock we can on child's children, namely AccessShareLock.
10665  */
10666  children = find_all_inheritors(RelationGetRelid(child_rel),
10668 
10669  if (list_member_oid(children, RelationGetRelid(parent_rel)))
10670  ereport(ERROR,
10671  (errcode(ERRCODE_DUPLICATE_TABLE),
10672  errmsg("circular inheritance not allowed"),
10673  errdetail("\"%s\" is already a child of \"%s\".",
10674  parent->relname,
10675  RelationGetRelationName(child_rel))));
10676 
10677  /* If parent has OIDs then child must have OIDs */
10678  if (parent_rel->rd_rel->relhasoids && !child_rel->rd_rel->relhasoids)
10679  ereport(ERROR,
10680  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
10681  errmsg("table \"%s\" without OIDs cannot inherit from table \"%s\" with OIDs",
10682  RelationGetRelationName(child_rel),
10683  RelationGetRelationName(parent_rel))));
10684 
10685  /* OK to create inheritance */
10686  CreateInheritance(child_rel, parent_rel);
10687 
10689  RelationGetRelid(parent_rel));
10690 
10691  /* keep our lock on the parent relation until commit */
10692  heap_close(parent_rel, NoLock);
10693 
10694  return address;
10695 }
#define RelationRelationId
Definition: pg_class.h:29
bool rd_islocaltemp
Definition: rel.h:90
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
#define ATT_TABLE
Definition: tablecmds.c:278
static void CreateInheritance(Relation child_rel, Relation parent_rel)
Definition: tablecmds.c:10705
char * relname
Definition: primnodes.h:68
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define RelationGetRelationName(relation)
Definition: rel.h:437
#define ereport(elevel, rest)
Definition: elog.h:122
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1315
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define NULL
Definition: c.h:229
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:158
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void ATSimplePermissions(Relation rel, int allowed_targets)
Definition: tablecmds.c:4602
#define RELPERSISTENCE_TEMP
Definition: pg_class.h:172
Definition: pg_list.h:45
#define ATT_FOREIGN_TABLE
Definition: tablecmds.c:283
#define RelationGetRelid(relation)
Definition: rel.h:417
static ObjectAddress ATExecAddOf ( Relation  rel,
const TypeName ofTypename,
LOCKMODE  lockmode 
)
static

Definition at line 11406 of file tablecmds.c.

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

Referenced by ATExecCmd().

11407 {
11408  Oid relid = RelationGetRelid(rel);
11409  Type typetuple;
11410  Oid typeid;
11411  Relation inheritsRelation,
11412  relationRelation;
11413  SysScanDesc scan;
11414  ScanKeyData key;
11415  AttrNumber table_attno,
11416  type_attno;
11417  TupleDesc typeTupleDesc,
11418  tableTupleDesc;
11419  ObjectAddress tableobj,
11420  typeobj;
11421  HeapTuple classtuple;
11422 
11423  /* Validate the type. */
11424  typetuple = typenameType(NULL, ofTypename, NULL);
11425  check_of_type(typetuple);
11426  typeid = HeapTupleGetOid(typetuple);
11427 
11428  /* Fail if the table has any inheritance parents. */
11429  inheritsRelation = heap_open(InheritsRelationId, AccessShareLock);
11430  ScanKeyInit(&key,
11432  BTEqualStrategyNumber, F_OIDEQ,
11433  ObjectIdGetDatum(relid));
11434  scan = systable_beginscan(inheritsRelation, InheritsRelidSeqnoIndexId,
11435  true, NULL, 1, &key);
11437  ereport(ERROR,
11438  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
11439  errmsg("typed tables cannot inherit")));
11440  systable_endscan(scan);
11441  heap_close(inheritsRelation, AccessShareLock);
11442 
11443  /*
11444  * Check the tuple descriptors for compatibility. Unlike inheritance, we
11445  * require that the order also match. However, attnotnull need not match.
11446  * Also unlike inheritance, we do not require matching relhasoids.
11447  */
11448  typeTupleDesc = lookup_rowtype_tupdesc(typeid, -1);
11449  tableTupleDesc = RelationGetDescr(rel);
11450  table_attno = 1;
11451  for (type_attno = 1; type_attno <= typeTupleDesc->natts; type_attno++)
11452  {
11453  Form_pg_attribute type_attr,
11454  table_attr;
11455  const char *type_attname,
11456  *table_attname;
11457 
11458  /* Get the next non-dropped type attribute. */
11459  type_attr = typeTupleDesc->attrs[type_attno - 1];
11460  if (type_attr->attisdropped)
11461  continue;
11462  type_attname = NameStr(type_attr->attname);
11463 
11464  /* Get the next non-dropped table attribute. */
11465  do
11466  {
11467  if (table_attno > tableTupleDesc->natts)
11468  ereport(ERROR,
11469  (errcode(ERRCODE_DATATYPE_MISMATCH),
11470  errmsg("table is missing column \"%s\"",
11471  type_attname)));
11472  table_attr = tableTupleDesc->attrs[table_attno++ - 1];
11473  } while (table_attr->attisdropped);
11474  table_attname = NameStr(table_attr->attname);
11475 
11476  /* Compare name. */
11477  if (strncmp(table_attname, type_attname, NAMEDATALEN) != 0)
11478  ereport(ERROR,
11479  (errcode(ERRCODE_DATATYPE_MISMATCH),
11480  errmsg("table has column \"%s\" where type requires \"%s\"",
11481  table_attname, type_attname)));
11482 
11483  /* Compare type. */
11484  if (table_attr->atttypid != type_attr->atttypid ||
11485  table_attr->atttypmod != type_attr->atttypmod ||
11486  table_attr->attcollation != type_attr->attcollation)
11487  ereport(ERROR,
11488  (errcode(ERRCODE_DATATYPE_MISMATCH),
11489  errmsg("table \"%s\" has different type for column \"%s\"",
11490  RelationGetRelationName(rel), type_attname)));
11491  }
11492  DecrTupleDescRefCount(typeTupleDesc);
11493 
11494  /* Any remaining columns at the end of the table had better be dropped. */
11495  for (; table_attno <= tableTupleDesc->natts; table_attno++)
11496  {
11497  Form_pg_attribute table_attr = tableTupleDesc->attrs[table_attno - 1];
11498 
11499  if (!table_attr->attisdropped)
11500  ereport(ERROR,
11501  (errcode(ERRCODE_DATATYPE_MISMATCH),
11502  errmsg("table has extra column \"%s\"",
11503  NameStr(table_attr->attname))));
11504  }
11505 
11506  /* If the table was already typed, drop the existing dependency. */
11507  if (rel->rd_rel->reloftype)
11508  drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype);
11509 
11510  /* Record a dependency on the new type. */
11511  tableobj.classId = RelationRelationId;
11512  tableobj.objectId = relid;
11513  tableobj.objectSubId = 0;
11514  typeobj.classId = TypeRelationId;
11515  typeobj.objectId = typeid;
11516  typeobj.objectSubId = 0;
11517  recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
11518 
11519  /* Update pg_class.reloftype */
11520  relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
11521  classtuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
11522  if (!HeapTupleIsValid(classtuple))
11523  elog(ERROR, "cache lookup failed for relation %u", relid);
11524  ((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
11525  CatalogTupleUpdate(relationRelation, &classtuple->t_self, classtuple);
11526 
11528 
11529  heap_freetuple(classtuple);
11530  heap_close(relationRelation, RowExclusiveLock);
11531 
11532  ReleaseSysCache(typetuple);
11533 
11534  return typeobj;
11535 }
#define Anum_pg_inherits_inhrelid
Definition: pg_inherits.h:50
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:247
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1257
#define RelationGetDescr(relation)
Definition: rel.h:429
#define RelationRelationId
Definition: pg_class.h:29
Form_pg_attribute * attrs
Definition: tupdesc.h:74
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
unsigned int Oid
Definition: postgres_ext.h:31
#define TypeRelationId
Definition: pg_type.h:34
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
int natts
Definition: tupdesc.h:73
#define NAMEDATALEN
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
void check_of_type(HeapTuple typetuple)
Definition: tablecmds.c:4959
static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid)
Definition: tablecmds.c:11355
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:437
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:184
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
void DecrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:334
#define InheritsRelidSeqnoIndexId
Definition: indexing.h:167
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define InheritsRelationId
Definition: pg_inherits.h:29
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:161
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:499
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:417
#define BTEqualStrategyNumber
Definition: stratnum.h:31
static ObjectAddress ATExecAlterColumnGenericOptions ( Relation  rel,
const char *  colName,
List options,
LOCKMODE  lockmode 
)
static

Definition at line 9030 of file tablecmds.c.

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

Referenced by ATExecCmd().

9034 {
9035  Relation ftrel;
9036  Relation attrel;
9037  ForeignServer *server;
9038  ForeignDataWrapper *fdw;
9039  HeapTuple tuple;
9040  HeapTuple newtuple;
9041  bool isnull;
9042  Datum repl_val[Natts_pg_attribute];
9043  bool repl_null[Natts_pg_attribute];
9044  bool repl_repl[Natts_pg_attribute];
9045  Datum datum;
9046  Form_pg_foreign_table fttableform;
9047  Form_pg_attribute atttableform;
9048  AttrNumber attnum;
9049  ObjectAddress address;
9050 
9051  if (options == NIL)
9052  return InvalidObjectAddress;
9053 
9054  /* First, determine FDW validator associated to the foreign table. */
9056  tuple = SearchSysCache1(FOREIGNTABLEREL, rel->rd_id);
9057  if (!HeapTupleIsValid(tuple))
9058  ereport(ERROR,
9059  (errcode(ERRCODE_UNDEFINED_OBJECT),
9060  errmsg("foreign table \"%s\" does not exist",
9061  RelationGetRelationName(rel))));
9062  fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
9063  server = GetForeignServer(fttableform->ftserver);
9064  fdw = GetForeignDataWrapper(server->fdwid);
9065 
9066  heap_close(ftrel, AccessShareLock);
9067  ReleaseSysCache(tuple);
9068 
9070  tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
9071  if (!HeapTupleIsValid(tuple))
9072  ereport(ERROR,
9073  (errcode(ERRCODE_UNDEFINED_COLUMN),
9074  errmsg("column \"%s\" of relation \"%s\" does not exist",
9075  colName, RelationGetRelationName(rel))));
9076 
9077  /* Prevent them from altering a system attribute */
9078  atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
9079  attnum = atttableform->attnum;
9080  if (attnum <= 0)
9081  ereport(ERROR,
9082  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9083  errmsg("cannot alter system column \"%s\"", colName)));
9084 
9085 
9086  /* Initialize buffers for new tuple values */
9087  memset(repl_val, 0, sizeof(repl_val));
9088  memset(repl_null, false, sizeof(repl_null));
9089  memset(repl_repl, false, sizeof(repl_repl));
9090 
9091  /* Extract the current options */
9092  datum = SysCacheGetAttr(ATTNAME,
9093  tuple,
9095  &isnull);
9096  if (isnull)
9097  datum = PointerGetDatum(NULL);
9098 
9099  /* Transform the options */
9101  datum,
9102  options,
9103  fdw->fdwvalidator);
9104 
9105  if (PointerIsValid(DatumGetPointer(datum)))
9106  repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
9107  else
9108  repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
9109 
9110  repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
9111 
9112  /* Everything looks good - update the tuple */
9113 
9114  newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
9115  repl_val, repl_null, repl_repl);
9116 
9117  CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
9118 
9120  RelationGetRelid(rel),
9121  atttableform->attnum);
9123  RelationGetRelid(rel), attnum);
9124 
9125  ReleaseSysCache(tuple);
9126 
9127  heap_close(attrel, RowExclusiveLock);
9128 
9129  heap_freetuple(newtuple);
9130 
9131  return address;
9132 }
#define NIL
Definition: pg_list.h:69
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define RelationGetDescr(relation)
Definition: rel.h:429
Datum transformGenericOptions(Oid catalogId, Datum oldOptions, List *options, Oid fdwvalidator)
Definition: foreigncmds.c:109
#define PointerGetDatum(X)
Definition: postgres.h:562
#define RelationRelationId
Definition: pg_class.h:29
#define AccessShareLock
Definition: lockdefs.h:36
#define AttributeRelationId
Definition: pg_attribute.h:33
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:152
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
Definition: foreign.c:35
FormData_pg_foreign_table * Form_pg_foreign_table
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:437
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:184
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
Oid rd_id
Definition: rel.h:116
ForeignServer * GetForeignServer(Oid serverid)
Definition: foreign.c:93
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1278
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:1204
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
#define Anum_pg_attribute_attfdwoptions
Definition: pg_attribute.h:212
#define DatumGetPointer(X)
Definition: postgres.h:555
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ForeignTableRelationId
#define Natts_pg_attribute
Definition: pg_attribute.h:191
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:793
#define PointerIsValid(pointer)
Definition: c.h:526
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:417
static ObjectAddress ATExecAlterColumnType ( AlteredTableInfo tab,
Relation  rel,
AlterTableCmd cmd,
LOCKMODE  lockmode 
)
static

Definition at line 8628 of file tablecmds.c.

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

Referenced by ATExecCmd().

8630 {
8631  char *colName = cmd->name;
8632  ColumnDef *def = (ColumnDef *) cmd->def;
8633  TypeName *typeName = def->typeName;
8634  HeapTuple heapTup;
8635  Form_pg_attribute attTup;
8636  AttrNumber attnum;
8637  HeapTuple typeTuple;
8638  Form_pg_type tform;
8639  Oid targettype;
8640  int32 targettypmod;
8641  Oid targetcollid;
8642  Node *defaultexpr;
8643  Relation attrelation;
8644  Relation depRel;
8645  ScanKeyData key[3];
8646  SysScanDesc scan;
8647  HeapTuple depTup;
8648  ObjectAddress address;
8649 
8651 
8652  /* Look up the target column */
8653  heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
8654  if (!HeapTupleIsValid(heapTup)) /* shouldn't happen */
8655  ereport(ERROR,
8656  (errcode(ERRCODE_UNDEFINED_COLUMN),
8657  errmsg("column \"%s\" of relation \"%s\" does not exist",
8658  colName, RelationGetRelationName(rel))));
8659  attTup = (Form_pg_attribute) GETSTRUCT(heapTup);
8660  attnum = attTup->attnum;
8661 
8662  /* Check for multiple ALTER TYPE on same column --- can't cope */
8663  if (attTup->atttypid != tab->oldDesc->attrs[attnum - 1]->atttypid ||
8664  attTup->atttypmod != tab->oldDesc->attrs[attnum - 1]->atttypmod)
8665  ereport(ERROR,
8666  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8667  errmsg("cannot alter type of column \"%s\" twice",
8668  colName)));
8669 
8670  /* Look up the target type (should not fail, since prep found it) */
8671  typeTuple = typenameType(NULL, typeName, &targettypmod);
8672  tform = (Form_pg_type) GETSTRUCT(typeTuple);
8673  targettype = HeapTupleGetOid(typeTuple);
8674  /* And the collation */
8675  targetcollid = GetColumnDefCollation(NULL, def, targettype);
8676 
8677  /*
8678  * If there is a default expression for the column, get it and ensure we
8679  * can coerce it to the new datatype. (We must do this before changing
8680  * the column type, because build_column_default itself will try to
8681  * coerce, and will not issue the error message we want if it fails.)
8682  *
8683  * We remove any implicit coercion steps at the top level of the old
8684  * default expression; this has been agreed to satisfy the principle of
8685  * least surprise. (The conversion to the new column type should act like
8686  * it started from what the user sees as the stored expression, and the
8687  * implicit coercions aren't going to be shown.)
8688  */
8689  if (attTup->atthasdef)
8690  {
8691  defaultexpr = build_column_default(rel, attnum);
8692  Assert(defaultexpr);
8693  defaultexpr = strip_implicit_coercions(defaultexpr);
8694  defaultexpr = coerce_to_target_type(NULL, /* no UNKNOWN params */
8695  defaultexpr, exprType(defaultexpr),
8696  targettype, targettypmod,
8699  -1);
8700  if (defaultexpr == NULL)
8701  ereport(ERROR,
8702  (errcode(ERRCODE_DATATYPE_MISMATCH),
8703  errmsg("default for column \"%s\" cannot be cast automatically to type %s",
8704  colName, format_type_be(targettype))));
8705  }
8706  else
8707  defaultexpr = NULL;
8708 
8709  /*
8710  * Find everything that depends on the column (constraints, indexes, etc),
8711  * and record enough information to let us recreate the objects.
8712  *
8713  * The actual recreation does not happen here, but only after we have
8714  * performed all the individual ALTER TYPE operations. We have to save
8715  * the info before executing ALTER TYPE, though, else the deparser will
8716  * get confused.
8717  *
8718  * There could be multiple entries for the same object, so we must check
8719  * to ensure we process each one only once. Note: we assume that an index
8720  * that implements a constraint will not show a direct dependency on the
8721  * column.
8722  */
8724 
8725  ScanKeyInit(&key[0],
8727  BTEqualStrategyNumber, F_OIDEQ,
8729  ScanKeyInit(&key[1],
8731  BTEqualStrategyNumber, F_OIDEQ,
8733  ScanKeyInit(&key[2],
8735  BTEqualStrategyNumber, F_INT4EQ,
8736  Int32GetDatum((int32) attnum));
8737 
8738  scan = systable_beginscan(depRel, DependReferenceIndexId, true,
8739  NULL, 3, key);
8740 
8741  while (HeapTupleIsValid(depTup = systable_getnext(scan)))
8742  {
8743  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
8744  ObjectAddress foundObject;
8745 
8746  /* We don't expect any PIN dependencies on columns */
8747  if (foundDep->deptype == DEPENDENCY_PIN)
8748  elog(ERROR, "cannot alter type of a pinned column");
8749 
8750  foundObject.classId = foundDep->classid;
8751  foundObject.objectId = foundDep->objid;
8752  foundObject.objectSubId = foundDep->objsubid;
8753 
8754  switch (getObjectClass(&foundObject))
8755  {
8756  case OCLASS_CLASS:
8757  {
8758  char relKind = get_rel_relkind(foundObject.objectId);
8759 
8760  if (relKind == RELKIND_INDEX)
8761  {
8762  Assert(foundObject.objectSubId == 0);
8763  if (!list_member_oid(tab->changedIndexOids, foundObject.objectId))
8764  {
8766  foundObject.objectId);
8768  pg_get_indexdef_string(foundObject.objectId));
8769  }
8770  }
8771  else if (relKind == RELKIND_SEQUENCE)
8772  {
8773  /*
8774  * This must be a SERIAL column's sequence. We need
8775  * not do anything to it.
8776  */
8777  Assert(foundObject.objectSubId == 0);
8778  }
8779  else
8780  {
8781  /* Not expecting any other direct dependencies... */
8782  elog(ERROR, "unexpected object depending on column: %s",
8783  getObjectDescription(&foundObject));
8784  }
8785  break;
8786  }
8787 
8788  case OCLASS_CONSTRAINT:
8789  Assert(foundObject.objectSubId == 0);
8791  foundObject.objectId))
8792  {
8793  char *defstring = pg_get_constraintdef_command(foundObject.objectId);
8794 
8795  /*
8796  * Put NORMAL dependencies at the front of the list and
8797  * AUTO dependencies at the back. This makes sure that
8798  * foreign-key constraints depending on this column will
8799  * be dropped before unique or primary-key constraints of
8800  * the column; which we must have because the FK
8801  * constraints depend on the indexes belonging to the
8802  * unique constraints.
8803  */
8804  if (foundDep->deptype == DEPENDENCY_NORMAL)
8805  {
8806  tab->changedConstraintOids =
8807  lcons_oid(foundObject.objectId,
8808  tab->changedConstraintOids);
8809  tab->changedConstraintDefs =
8810  lcons(defstring,
8811  tab->changedConstraintDefs);
8812  }
8813  else
8814  {
8815  tab->changedConstraintOids =
8817  foundObject.objectId);
8818  tab->changedConstraintDefs =
8820  defstring);
8821  }
8822  }
8823  break;
8824 
8825  case OCLASS_REWRITE:
8826  /* XXX someday see if we can cope with revising views */
8827  ereport(ERROR,
8828  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8829  errmsg("cannot alter type of a column used by a view or rule"),
8830  errdetail("%s depends on column \"%s\"",
8831  getObjectDescription(&foundObject),
8832  colName)));
8833  break;
8834 
8835  case OCLASS_TRIGGER:
8836 
8837  /*
8838  * A trigger can depend on a column because the column is
8839  * specified as an update target, or because the column is
8840  * used in the trigger's WHEN condition. The first case would
8841  * not require any extra work, but the second case would
8842  * require updating the WHEN expression, which will take a
8843  * significant amount of new code. Since we can't easily tell
8844  * which case applies, we punt for both. FIXME someday.
8845  */
8846  ereport(ERROR,
8847  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8848  errmsg("cannot alter type of a column used in a trigger definition"),
8849  errdetail("%s depends on column \"%s\"",
8850  getObjectDescription(&foundObject),
8851  colName)));
8852  break;
8853 
8854  case OCLASS_POLICY:
8855 
8856  /*
8857  * A policy can depend on a column because the column is
8858  * specified in the policy's USING or WITH CHECK qual
8859  * expressions. It might be possible to rewrite and recheck
8860  * the policy expression, but punt for now. It's certainly
8861  * easy enough to remove and recreate the policy; still, FIXME
8862  * someday.
8863  */
8864  ereport(ERROR,
8865  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8866  errmsg("cannot alter type of a column used in a policy definition"),
8867  errdetail("%s depends on column \"%s\"",
8868  getObjectDescription(&foundObject),
8869  colName)));
8870  break;
8871 
8872  case OCLASS_DEFAULT:
8873 
8874  /*
8875  * Ignore the column's default expression, since we will fix
8876  * it below.
8877  */
8878  Assert(defaultexpr);
8879  break;
8880 
8881  case OCLASS_PROC:
8882  case OCLASS_TYPE:
8883  case OCLASS_CAST:
8884  case OCLASS_COLLATION:
8885  case OCLASS_CONVERSION:
8886  case OCLASS_LANGUAGE:
8887  case OCLASS_LARGEOBJECT:
8888  case OCLASS_OPERATOR:
8889  case OCLASS_OPCLASS:
8890  case OCLASS_OPFAMILY:
8891  case OCLASS_AMOP:
8892  case OCLASS_AMPROC:
8893  case OCLASS_SCHEMA:
8894  case OCLASS_TSPARSER:
8895  case OCLASS_TSDICT:
8896  case OCLASS_TSTEMPLATE:
8897  case OCLASS_TSCONFIG:
8898  case OCLASS_ROLE:
8899  case OCLASS_DATABASE:
8900  case OCLASS_TBLSPACE:
8901  case OCLASS_FDW:
8902  case OCLASS_FOREIGN_SERVER:
8903  case OCLASS_USER_MAPPING:
8904  case OCLASS_DEFACL:
8905  case OCLASS_EXTENSION:
8906 
8907  /*
8908  * We don't expect any of these sorts of objects to depend on
8909  * a column.
8910  */
8911  elog(ERROR, "unexpected object depending on column: %s",
8912  getObjectDescription(&foundObject));
8913  break;
8914 
8915  default:
8916  elog(ERROR, "unrecognized object class: %u",
8917  foundObject.classId);
8918  }
8919  }
8920 
8921  systable_endscan(scan);
8922 
8923  /*
8924  * Now scan for dependencies of this column on other things. The only
8925  * thing we should find is the dependency on the column datatype, which we
8926  * want to remove, and possibly a collation dependency.
8927  */
8928  ScanKeyInit(&key[0],
8930  BTEqualStrategyNumber, F_OIDEQ,
8932  ScanKeyInit(&key[1],
8934  BTEqualStrategyNumber, F_OIDEQ,
8936  ScanKeyInit(&key[2],
8938  BTEqualStrategyNumber, F_INT4EQ,
8939  Int32GetDatum((int32) attnum));
8940 
8941  scan = systable_beginscan(depRel, DependDependerIndexId, true,
8942  NULL, 3, key);
8943 
8944  while (HeapTupleIsValid(depTup = systable_getnext(scan)))
8945  {
8946  Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup);
8947 
8948  if (foundDep->deptype != DEPENDENCY_NORMAL)
8949  elog(ERROR, "found unexpected dependency type '%c'",
8950  foundDep->deptype);
8951  if (!(foundDep->refclassid == TypeRelationId &&
8952  foundDep->refobjid == attTup->atttypid) &&
8953  !(foundDep->refclassid == CollationRelationId &&
8954  foundDep->refobjid == attTup->attcollation))
8955  elog(ERROR, "found unexpected dependency for column");
8956 
8957  CatalogTupleDelete(depRel, &depTup->t_self);
8958  }
8959 
8960  systable_endscan(scan);
8961 
8962  heap_close(depRel, RowExclusiveLock);
8963 
8964  /*
8965  * Here we go --- change the recorded column type and collation. (Note
8966  * heapTup is a copy of the syscache entry, so okay to scribble on.)
8967  */
8968  attTup->atttypid = targettype;
8969  attTup->atttypmod = targettypmod;
8970  attTup->attcollation = targetcollid;
8971  attTup->attndims = list_length(typeName->arrayBounds);
8972  attTup->attlen = tform->typlen;
8973  attTup->attbyval = tform->typbyval;
8974  attTup->attalign = tform->typalign;
8975  attTup->attstorage = tform->typstorage;
8976 
8977  ReleaseSysCache(typeTuple);
8978 
8979  CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup);
8980 
8981  heap_close(attrelation, RowExclusiveLock);
8982 
8983  /* Install dependencies on new datatype and collation */
8984  add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype);
8985  add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid);
8986 
8987  /*
8988  * Drop any pg_statistic entry for the column, since it's now wrong type
8989  */
8990  RemoveStatistics(RelationGetRelid(rel), attnum);
8991 
8993  RelationGetRelid(rel), attnum);
8994 
8995  /*
8996  * Update the default, if present, by brute force --- remove and re-add
8997  * the default. Probably unsafe to take shortcuts, since the new version
8998  * may well have additional dependencies. (It's okay to do this now,
8999  * rather than after other ALTER TYPE commands, since the default won't
9000  * depend on other column types.)
9001  */
9002  if (defaultexpr)
9003  {
9004  /* Must make new row visible since it will be updated again */
9006 
9007  /*
9008  * We use RESTRICT here for safety, but at present we do not expect
9009  * anything to depend on the default.
9010  */
9011  RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
9012  true);
9013 
9014  StoreAttrDefault(rel, attnum, defaultexpr, true);
9015  }
9016 
9018  RelationGetRelid(rel), attnum);
9019 
9020  /* Cleanup */
9021  heap_freetuple(heapTup);
9022 
9023  return address;
9024 }
#define Anum_pg_depend_refobjid
Definition: pg_depend.h:72
#define Anum_pg_depend_refobjsubid
Definition: pg_depend.h:73
#define Anum_pg_depend_refclassid
Definition: pg_depend.h:71
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:247
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1769
#define RelationRelationId
Definition: pg_class.h:29
#define DependReferenceIndexId
Definition: indexing.h:147
#define DependDependerIndexId
Definition: indexing.h:145
#define DependRelationId
Definition: pg_depend.h:29
Form_pg_attribute * attrs
Definition: tupdesc.h:74
char * pg_get_indexdef_string(Oid indexrelid)
Definition: ruleutils.c:1119
Definition: nodes.h:504
List * changedConstraintDefs
Definition: tablecmds.c:173
#define AttributeRelationId
Definition: pg_attribute.h:33
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:255
List * lcons_oid(Oid datum, List *list)
Definition: list.c:295
#define heap_close(r, l)
Definition: heapam.h:97
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
unsigned int Oid
Definition: postgres_ext.h:31
#define TypeRelationId
Definition: pg_type.h:34
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
ObjectClass getObjectClass(const ObjectAddress *object)
Definition: dependency.c:2318
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
#define Anum_pg_depend_objsubid
Definition: pg_depend.h:70