📄 tablecmds.c
字号:
/*------------------------------------------------------------------------- * * tablecmds.c * Commands for creating and altering table structures and settings * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.174.2.2 2006/01/30 16:19:04 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/tuptoaster.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/pg_constraint.h"#include "catalog/pg_depend.h"#include "catalog/pg_inherits.h"#include "catalog/pg_namespace.h"#include "catalog/pg_opclass.h"#include "catalog/pg_trigger.h"#include "catalog/pg_type.h"#include "commands/cluster.h"#include "commands/defrem.h"#include "commands/tablecmds.h"#include "commands/tablespace.h"#include "commands/trigger.h"#include "commands/typecmds.h"#include "executor/executor.h"#include "lib/stringinfo.h"#include "miscadmin.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/plancat.h"#include "optimizer/prep.h"#include "parser/analyze.h"#include "parser/gramparse.h"#include "parser/parser.h"#include "parser/parse_clause.h"#include "parser/parse_coerce.h"#include "parser/parse_expr.h"#include "parser/parse_oper.h"#include "parser/parse_relation.h"#include "parser/parse_type.h"#include "rewrite/rewriteHandler.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/syscache.h"/* * ON COMMIT action list */typedef struct OnCommitItem{ Oid relid; /* relid of relation */ OnCommitAction oncommit; /* what to do at end of xact */ /* * If this entry was created during the current transaction, * creating_subid is the ID of the creating subxact; if created in a prior * transaction, creating_subid is zero. If deleted during the current * transaction, deleting_subid is the ID of the deleting subxact; if no * deletion request is pending, deleting_subid is zero. */ SubTransactionId creating_subid; SubTransactionId deleting_subid;} OnCommitItem;static List *on_commits = NIL;/* * State information for ALTER TABLE * * The pending-work queue for an ALTER TABLE is a List of AlteredTableInfo * structs, one for each table modified by the operation (the named table * plus any child tables that are affected). We save lists of subcommands * to apply to this table (possibly modified by parse transformation steps); * these lists will be executed in Phase 2. If a Phase 3 step is needed, * necessary information is stored in the constraints and newvals lists. * * Phase 2 is divided into multiple passes; subcommands are executed in * a pass determined by subcommand type. */#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 *//* We could support a RENAME COLUMN pass here, but not currently used */#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 9typedef struct AlteredTableInfo{ /* Information saved before any work commences: */ Oid relid; /* Relation to work on */ char relkind; /* Its relkind */ TupleDesc oldDesc; /* Pre-modification tuple descriptor */ /* Information saved by Phase 1 for Phase 2: */ List *subcmds[AT_NUM_PASSES]; /* Lists of AlterTableCmd */ /* Information saved by Phases 1/2 for Phase 3: */ List *constraints; /* List of NewConstraint */ List *newvals; /* List of NewColumnValue */ Oid newTableSpace; /* new tablespace; 0 means no change */ /* Objects to rebuild after completing ALTER TYPE operations */ List *changedConstraintOids; /* OIDs of constraints to rebuild */ List *changedConstraintDefs; /* string definitions of same */ List *changedIndexOids; /* OIDs of indexes to rebuild */ List *changedIndexDefs; /* string definitions of same */} AlteredTableInfo;/* Struct describing one new constraint to check in Phase 3 scan */typedef struct NewConstraint{ char *name; /* Constraint name, or NULL if none */ ConstrType contype; /* CHECK, NOT_NULL, or FOREIGN */ AttrNumber attnum; /* only relevant for NOT_NULL */ Oid refrelid; /* PK rel, if FOREIGN */ Node *qual; /* Check expr or FkConstraint struct */ List *qualstate; /* Execution state for CHECK */} NewConstraint;/* * Struct describing one new column value that needs to be computed during * Phase 3 copy (this could be either a new column with a non-null default, or * a column that we're changing the type of). Columns without such an entry * are just copied from the old table during ATRewriteTable. Note that the * expr is an expression over *old* table values. */typedef struct NewColumnValue{ AttrNumber attnum; /* which column */ Expr *expr; /* expression to compute */ ExprState *exprstate; /* execution state */} NewColumnValue;static List *MergeAttributes(List *schema, List *supers, bool istemp, List **supOids, List **supconstr, int *supOidCount);static bool change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);static void StoreCatalogInheritance(Oid relationId, List *supers);static int findAttrByName(const char *attributeName, List *schema);static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);static bool needs_toast_table(Relation rel);static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid);static void AlterSeqNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, const char *newNspName);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 validateForeignKeyConstraint(FkConstraint *fkconstraint, Relation rel, Relation pkrel);static void createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint, Oid constrOid);static char *fkMatchTypeToString(char match_type);static void ATController(Relation rel, List *cmds, bool recurse);static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing);static void ATRewriteCatalogs(List **wqueue);static void ATExecCmd(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd);static void ATRewriteTables(List **wqueue);static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap);static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel);static void ATSimplePermissions(Relation rel, bool allowView);static void ATSimpleRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse);static void ATOneLevelRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd);static void find_composite_type_dependencies(Oid typeOid, const char *origTblName);static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd);static void ATExecAddColumn(AlteredTableInfo *tab, Relation rel, ColumnDef *colDef);static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);static void add_column_support_dependency(Oid relid, int32 attnum, RangeVar *support);static void ATExecDropNotNull(Relation rel, const char *colName);static void ATExecSetNotNull(AlteredTableInfo *tab, Relation rel, const char *colName);static void ATExecColumnDefault(Relation rel, const char *colName, Node *newDefault);static void ATPrepSetStatistics(Relation rel, const char *colName, Node *flagValue);static void ATExecSetStatistics(Relation rel, const char *colName, Node *newValue);static void ATExecSetStorage(Relation rel, const char *colName, Node *newValue);static void ATExecDropColumn(Relation rel, const char *colName, DropBehavior behavior, bool recurse, bool recursing);static void ATExecAddIndex(AlteredTableInfo *tab, Relation rel, IndexStmt *stmt, bool is_rebuild);static void ATExecAddConstraint(AlteredTableInfo *tab, Relation rel, Node *newConstraint);static void ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, FkConstraint *fkconstraint);static void ATPrepDropConstraint(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd);static void ATExecDropConstraint(Relation rel, const char *constrName, DropBehavior behavior, bool quiet);static void ATPrepAlterColumnType(List **wqueue, AlteredTableInfo *tab, Relation rel, bool recurse, bool recursing, AlterTableCmd *cmd);static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, const char *colName, TypeName *typename);static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab);static void ATPostAlterTypeParse(char *cmd, List **wqueue);static void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing);static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId);static void ATExecClusterOn(Relation rel, const char *indexName);static void ATExecDropCluster(Relation rel);static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename);static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace);static void ATExecEnableDisableTrigger(Relation rel, char *trigname, bool enable, bool skip_system);static void copy_relation_data(Relation rel, SMgrRelation dst);static void update_ri_trigger_args(Oid relid, const char *oldname, const char *newname, bool fk_scan, bool update_relname);/* ---------------------------------------------------------------- * DefineRelation * Creates a new relation. * * If successful, returns the OID of the new relation. * ---------------------------------------------------------------- */OidDefineRelation(CreateStmt *stmt, char relkind){ char relname[NAMEDATALEN]; Oid namespaceId; List *schema = stmt->tableElts; Oid relationId; Oid tablespaceId; Relation rel; TupleDesc descriptor; List *inheritOids; List *old_constraints; bool localHasOids; int parentOidCount; List *rawDefaults; ListCell *listptr; int i; AttrNumber attnum; /* * Truncate relname to appropriate length (probably a waste of time, as * parser should have done this already). */ StrNCpy(relname, stmt->relation->relname, NAMEDATALEN); /* * Check consistency of arguments */ if (stmt->oncommit != ONCOMMIT_NOOP && !stmt->relation->istemp) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("ON COMMIT can only be used on temporary tables"))); /* * Look up the namespace in which we are supposed to create the relation. * Check we have permission to create there. Skip check if bootstrapping, * since permissions machinery may not be working yet. */ namespaceId = RangeVarGetCreationNamespace(stmt->relation); if (!IsBootstrapProcessingMode()) { AclResult aclresult; aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceId)); } /* * Select tablespace to use. If not specified, use default_tablespace * (which may in turn default to database's default). */ if (stmt->tablespacename) { tablespaceId = get_tablespace_oid(stmt->tablespacename); if (!OidIsValid(tablespaceId)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace \"%s\" does not exist", stmt->tablespacename))); } else { tablespaceId = GetDefaultTablespace(); /* note InvalidOid is OK in this case */ } /* Check permissions except when using database's default */ if (OidIsValid(tablespaceId)) { AclResult aclresult; aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_TABLESPACE, get_tablespace_name(tablespaceId)); } /* * Look up inheritance ancestors and generate relation schema, including * inherited attributes. */ schema = MergeAttributes(schema, stmt->inhRelations, stmt->relation->istemp, &inheritOids, &old_constraints, &parentOidCount); /* * Create a relation descriptor from the relation schema and create the * relation. Note that in this stage only inherited (pre-cooked) defaults * and constraints will be included into the new relation. * (BuildDescForRelation takes care of the inherited defaults, but we have * to copy inherited constraints here.) */ descriptor = BuildDescForRelation(schema); localHasOids = interpretOidsOption(stmt->hasoids); descriptor->tdhasoid = (localHasOids || parentOidCount > 0); if (old_constraints != NIL) { ConstrCheck *check = (ConstrCheck *) palloc0(list_length(old_constraints) * sizeof(ConstrCheck)); int ncheck = 0; foreach(listptr, old_constraints) { Constraint *cdef = (Constraint *) lfirst(listptr); bool dup = false; if (cdef->contype != CONSTR_CHECK) continue; Assert(cdef->name != NULL); Assert(cdef->raw_expr == NULL && cdef->cooked_expr != NULL); /* * In multiple-inheritance situations, it's possible to inherit * the same grandparent constraint through multiple parents. * Hence, discard inherited constraints that match as to both name * and expression. Otherwise, gripe if the names conflict. */ for (i = 0; i < ncheck; i++) { if (strcmp(check[i].ccname, cdef->name) != 0) continue; if (strcmp(check[i].ccbin, cdef->cooked_expr) == 0) { dup = true; break; } ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("duplicate check constraint name \"%s\"", cdef->name))); } if (!dup) { check[ncheck].ccname = cdef->name; check[ncheck].ccbin = pstrdup(cdef->cooked_expr); ncheck++; } } if (ncheck > 0) { if (descriptor->constr == NULL) { descriptor->constr = (TupleConstr *) palloc(sizeof(TupleConstr)); descriptor->constr->defval = NULL; descriptor->constr->num_defval = 0; descriptor->constr->has_not_null = false; } descriptor->constr->num_check = ncheck; descriptor->constr->check = check; } } relationId = heap_create_with_catalog(relname, namespaceId, tablespaceId, InvalidOid, GetUserId(), descriptor, relkind, false,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -