📄 heap.c
字号:
/*------------------------------------------------------------------------- * * heap.c * code to create and destroy POSTGRES heap relations * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.292.2.2 2006/04/24 01:40:39 alvherre Exp $ * * * INTERFACE ROUTINES * heap_create() - Create an uncataloged heap relation * heap_create_with_catalog() - Create a cataloged relation * heap_drop_with_catalog() - Removes named relation from catalogs * * NOTES * this code taken from access/heap/create.c, which contains * the old heap_create_with_catalog, amcreate, and amdestroy. * those routines will soon call these routines using the function * manager, * just like the poorly named "NewXXX" routines do. The * "New" routines are all going to die soon, once and for all! * -cim 1/13/91 * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "access/genam.h"#include "catalog/catalog.h"#include "catalog/dependency.h"#include "catalog/heap.h"#include "catalog/index.h"#include "catalog/indexing.h"#include "catalog/pg_attrdef.h"#include "catalog/pg_constraint.h"#include "catalog/pg_inherits.h"#include "catalog/pg_namespace.h"#include "catalog/pg_statistic.h"#include "catalog/pg_type.h"#include "commands/tablecmds.h"#include "commands/trigger.h"#include "miscadmin.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/planmain.h"#include "optimizer/var.h"#include "parser/parse_coerce.h"#include "parser/parse_expr.h"#include "parser/parse_relation.h"#include "rewrite/rewriteRemove.h"#include "storage/smgr.h"#include "utils/builtins.h"#include "utils/fmgroids.h"#include "utils/inval.h"#include "utils/lsyscache.h"#include "utils/relcache.h"#include "utils/syscache.h"static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Oid new_type_oid, Oid relowner, char relkind);static Oid AddNewRelationType(const char *typeName, Oid typeNamespace, Oid new_rel_oid, char new_rel_kind);static void RelationRemoveInheritance(Oid relid);static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);static void StoreConstraints(Relation rel, TupleDesc tupdesc);static void SetRelationNumChecks(Relation rel, int numchecks);/* ---------------------------------------------------------------- * XXX UGLY HARD CODED BADNESS FOLLOWS XXX * * these should all be moved to someplace in the lib/catalog * module, if not obliterated first. * ---------------------------------------------------------------- *//* * Note: * Should the system special case these attributes in the future? * Advantage: consume much less space in the ATTRIBUTE relation. * Disadvantage: special cases will be all over the place. */static FormData_pg_attribute a1 = { 0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData), SelfItemPointerAttributeNumber, 0, -1, -1, false, 'p', 's', true, false, false, true, 0};static FormData_pg_attribute a2 = { 0, {"oid"}, OIDOID, 0, sizeof(Oid), ObjectIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0};static FormData_pg_attribute a3 = { 0, {"xmin"}, XIDOID, 0, sizeof(TransactionId), MinTransactionIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0};static FormData_pg_attribute a4 = { 0, {"cmin"}, CIDOID, 0, sizeof(CommandId), MinCommandIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0};static FormData_pg_attribute a5 = { 0, {"xmax"}, XIDOID, 0, sizeof(TransactionId), MaxTransactionIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0};static FormData_pg_attribute a6 = { 0, {"cmax"}, CIDOID, 0, sizeof(CommandId), MaxCommandIdAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0};/* * We decided to call this attribute "tableoid" rather than say * "classoid" on the basis that in the future there may be more than one * table of a particular class/type. In any case table is still the word * used in SQL. */static FormData_pg_attribute a7 = { 0, {"tableoid"}, OIDOID, 0, sizeof(Oid), TableOidAttributeNumber, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0};static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7};/* * This function returns a Form_pg_attribute pointer for a system attribute. * Note that we elog if the presented attno is invalid, which would only * happen if there's a problem upstream. */Form_pg_attributeSystemAttributeDefinition(AttrNumber attno, bool relhasoids){ if (attno >= 0 || attno < -(int) lengthof(SysAtt)) elog(ERROR, "invalid system attribute number %d", attno); if (attno == ObjectIdAttributeNumber && !relhasoids) elog(ERROR, "invalid system attribute number %d", attno); return SysAtt[-attno - 1];}/* * If the given name is a system attribute name, return a Form_pg_attribute * pointer for a prototype definition. If not, return NULL. */Form_pg_attributeSystemAttributeByName(const char *attname, bool relhasoids){ int j; for (j = 0; j < (int) lengthof(SysAtt); j++) { Form_pg_attribute att = SysAtt[j]; if (relhasoids || att->attnum != ObjectIdAttributeNumber) { if (strcmp(NameStr(att->attname), attname) == 0) return att; } } return NULL;}/* ---------------------------------------------------------------- * XXX END OF UGLY HARD CODED BADNESS XXX * ---------------------------------------------------------------- *//* ---------------------------------------------------------------- * heap_create - Create an uncataloged heap relation * * Note API change: the caller must now always provide the OID * to use for the relation. * * rel->rd_rel is initialized by RelationBuildLocalRelation, * and is mostly zeroes at return. * ---------------------------------------------------------------- */Relationheap_create(const char *relname, Oid relnamespace, Oid reltablespace, Oid relid, TupleDesc tupDesc, char relkind, bool shared_relation, bool allow_system_table_mods){ bool create_storage; Relation rel; /* The caller must have provided an OID for the relation. */ Assert(OidIsValid(relid)); /* * sanity checks */ if (!allow_system_table_mods && (IsSystemNamespace(relnamespace) || IsToastNamespace(relnamespace)) && IsNormalProcessingMode()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied to create \"%s.%s\"", get_namespace_name(relnamespace), relname), errdetail("System catalog modifications are currently disallowed."))); /* * Decide if we need storage or not, and handle a couple other special * cases for particular relkinds. */ switch (relkind) { case RELKIND_VIEW: case RELKIND_COMPOSITE_TYPE: create_storage = false; /* * Force reltablespace to zero if the relation has no physical * storage. This is mainly just for cleanliness' sake. */ reltablespace = InvalidOid; break; case RELKIND_SEQUENCE: create_storage = true; /* * Force reltablespace to zero for sequences, since we don't * support moving them around into different tablespaces. */ reltablespace = InvalidOid; break; default: create_storage = true; break; } /* * Never allow a pg_class entry to explicitly specify the database's * default tablespace in reltablespace; force it to zero instead. This * ensures that if the database is cloned with a different default * tablespace, the pg_class entry will still match where CREATE DATABASE * will put the physically copied relation. * * Yes, this is a bit of a hack. */ if (reltablespace == MyDatabaseTableSpace) reltablespace = InvalidOid; /* * build the relcache entry. */ rel = RelationBuildLocalRelation(relname, relnamespace, tupDesc, relid, reltablespace, shared_relation); /* * have the storage manager create the relation's disk file, if needed. */ if (create_storage) { Assert(rel->rd_smgr == NULL); RelationOpenSmgr(rel); smgrcreate(rel->rd_smgr, rel->rd_istemp, false); } return rel;}/* ---------------------------------------------------------------- * heap_create_with_catalog - Create a cataloged relation * * this is done in multiple steps: * * 1) CheckAttributeNamesTypes() is used to make certain the tuple * descriptor contains a valid set of attribute names and types * * 2) pg_class is opened and get_relname_relid() * performs a scan to ensure that no relation with the * same name already exists. * * 3) heap_create() is called to create the new relation on disk. * * 4) TypeCreate() is called to define a new type corresponding * to the new relation. * * 5) AddNewRelationTuple() is called to register the * relation in pg_class. * * 6) AddNewAttributeTuples() is called to register the * new relation's schema in pg_attribute. * * 7) StoreConstraints is called () - vadim 08/22/97 * * 8) the relations are closed and the new relation's oid * is returned. * * ---------------------------------------------------------------- *//* -------------------------------- * CheckAttributeNamesTypes * * this is used to make certain the tuple descriptor contains a * valid set of attribute names and datatypes. a problem simply * generates ereport(ERROR) which aborts the current transaction. * -------------------------------- */voidCheckAttributeNamesTypes(TupleDesc tupdesc, char relkind){ int i; int j; int natts = tupdesc->natts; /* Sanity check on column count */ if (natts < 0 || natts > MaxHeapAttributeNumber) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_COLUMNS), errmsg("tables can have at most %d columns", MaxHeapAttributeNumber))); /* * first check for collision with system attribute names * * Skip this for a view or type relation, since those don't have system * attributes. */ if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) { for (i = 0; i < natts; i++) { if (SystemAttributeByName(NameStr(tupdesc->attrs[i]->attname), tupdesc->tdhasoid) != NULL) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("column name \"%s\" conflicts with a system column name", NameStr(tupdesc->attrs[i]->attname)))); } } /* * next check for repeated attribute names */ for (i = 1; i < natts; i++) { for (j = 0; j < i; j++) { if (strcmp(NameStr(tupdesc->attrs[j]->attname), NameStr(tupdesc->attrs[i]->attname)) == 0) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("column name \"%s\" is duplicated", NameStr(tupdesc->attrs[j]->attname)))); } } /* * next check the attribute types */ for (i = 0; i < natts; i++) { CheckAttributeType(NameStr(tupdesc->attrs[i]->attname), tupdesc->attrs[i]->atttypid); }}/* -------------------------------- * CheckAttributeType * * Verify that the proposed datatype of an attribute is legal. * This is needed because there are types (and pseudo-types) * in the catalogs that we do not support as elements of real tuples. * -------------------------------- */voidCheckAttributeType(const char *attname, Oid atttypid){ char att_typtype = get_typtype(atttypid); /* * Warn user, but don't fail, if column to be created has UNKNOWN type * (usually as a result of a 'retrieve into' - jolly) * * Refuse any attempt to create a pseudo-type column. */ if (atttypid == UNKNOWNOID) ereport(WARNING, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("column \"%s\" has type \"unknown\"", attname), errdetail("Proceeding with relation creation anyway."))); else if (att_typtype == 'p') { /* Special hack for pg_statistic: allow ANYARRAY during initdb */ if (atttypid != ANYARRAYOID || IsUnderPostmaster) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("column \"%s\" has pseudo-type %s", attname, format_type_be(atttypid)))); }}/* -------------------------------- * AddNewAttributeTuples * * this registers the new relation's schema by adding * tuples to pg_attribute. * -------------------------------- */static voidAddNewAttributeTuples(Oid new_rel_oid, TupleDesc tupdesc, char relkind, bool oidislocal, int oidinhcount){ const Form_pg_attribute *dpp; int i; HeapTuple tup; Relation rel; CatalogIndexState indstate; int natts = tupdesc->natts; ObjectAddress myself, referenced; /* * open pg_attribute and its indexes. */ rel = heap_open(AttributeRelationId, RowExclusiveLock); indstate = CatalogOpenIndexes(rel); /* * First we add the user attributes. This is also a convenient place to * add dependencies on their datatypes. */ dpp = tupdesc->attrs; for (i = 0; i < natts; i++) { /* Fill in the correct relation OID */ (*dpp)->attrelid = new_rel_oid; /* Make sure these are OK, too */ (*dpp)->attstattarget = -1; (*dpp)->attcacheoff = -1; tup = heap_addheader(Natts_pg_attribute, false, ATTRIBUTE_TUPLE_SIZE, (void *) *dpp); simple_heap_insert(rel, tup); CatalogIndexInsert(indstate, tup); heap_freetuple(tup); myself.classId = RelationRelationId; myself.objectId = new_rel_oid; myself.objectSubId = i + 1; referenced.classId = TypeRelationId; referenced.objectId = (*dpp)->atttypid; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); dpp++; } /* * Next we add the system attributes. Skip OID if rel has no OIDs. Skip * all for a view or type relation. We don't bother with making datatype * dependencies here, since presumably all these types are pinned. */ if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) { dpp = SysAtt; for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++) { if (tupdesc->tdhasoid || (*dpp)->attnum != ObjectIdAttributeNumber) { Form_pg_attribute attStruct; tup = heap_addheader(Natts_pg_attribute, false, ATTRIBUTE_TUPLE_SIZE, (void *) *dpp); attStruct = (Form_pg_attribute) GETSTRUCT(tup); /* Fill in the correct relation OID in the copied tuple */ attStruct->attrelid = new_rel_oid; /* Fill in correct inheritance info for the OID column */ if (attStruct->attnum == ObjectIdAttributeNumber) { attStruct->attislocal = oidislocal; attStruct->attinhcount = oidinhcount; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -