heap.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,069 行 · 第 1/4 页

C
2,069
字号
/*------------------------------------------------------------------------- * * heap.c *	  code to create and destroy POSTGRES heap relations * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.253 2003/09/25 06:57:57 petere 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/catname.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_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,					char relkind);static void AddNewRelationType(const char *typeName,				   Oid typeNamespace,				   Oid new_rel_oid,				   char new_rel_kind,				   Oid new_type_oid);static void RelationRemoveInheritance(Relation relation);static void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin);static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);static void StoreConstraints(Relation rel, TupleDesc tupdesc);static void SetRelationNumChecks(Relation rel, int numchecks);static void RemoveStatistics(Relation rel, AttrNumber attnum);/* ---------------------------------------------------------------- *				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', false, 'i', true, false, false, true, 0};static FormData_pg_attribute a2 = {	0, {"oid"}, OIDOID, 0, sizeof(Oid),	ObjectIdAttributeNumber, 0, -1, -1,	true, 'p', false, 'i', true, false, false, true, 0};static FormData_pg_attribute a3 = {	0, {"xmin"}, XIDOID, 0, sizeof(TransactionId),	MinTransactionIdAttributeNumber, 0, -1, -1,	true, 'p', false, 'i', true, false, false, true, 0};static FormData_pg_attribute a4 = {	0, {"cmin"}, CIDOID, 0, sizeof(CommandId),	MinCommandIdAttributeNumber, 0, -1, -1,	true, 'p', false, 'i', true, false, false, true, 0};static FormData_pg_attribute a5 = {	0, {"xmax"}, XIDOID, 0, sizeof(TransactionId),	MaxTransactionIdAttributeNumber, 0, -1, -1,	true, 'p', false, 'i', true, false, false, true, 0};static FormData_pg_attribute a6 = {	0, {"cmax"}, CIDOID, 0, sizeof(CommandId),	MaxCommandIdAttributeNumber, 0, -1, -1,	true, 'p', false, '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', false, 'i', true, false, false, true, 0};static 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 * *		rel->rd_rel is initialized by RelationBuildLocalRelation, *		and is mostly zeroes at return. * *		Remove the system relation specific code to elsewhere eventually. * * If storage_create is TRUE then heap_storage_create is called here, * else caller must call heap_storage_create later (or not at all, * if the relation doesn't need physical storage). * ---------------------------------------------------------------- */Relationheap_create(const char *relname,			Oid relnamespace,			TupleDesc tupDesc,			bool shared_relation,			bool storage_create,			bool allow_system_table_mods){	Oid			relid;	Oid			dbid = shared_relation ? InvalidOid : MyDatabaseId;	bool		nailme = false;	RelFileNode rnode;	Relation	rel;	/*	 * 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.")));	/*	 * Real ugly stuff to assign the proper relid in the relation	 * descriptor follows.	Note that only "bootstrapped" relations whose	 * OIDs are hard-coded in pg_class.h should be listed here.  We also	 * have to recognize those rels that must be nailed in cache.	 */	if (IsSystemNamespace(relnamespace))	{		if (strcmp(TypeRelationName, relname) == 0)		{			nailme = true;			relid = RelOid_pg_type;		}		else if (strcmp(AttributeRelationName, relname) == 0)		{			nailme = true;			relid = RelOid_pg_attribute;		}		else if (strcmp(ProcedureRelationName, relname) == 0)		{			nailme = true;			relid = RelOid_pg_proc;		}		else if (strcmp(RelationRelationName, relname) == 0)		{			nailme = true;			relid = RelOid_pg_class;		}		else if (strcmp(ShadowRelationName, relname) == 0)			relid = RelOid_pg_shadow;		else if (strcmp(GroupRelationName, relname) == 0)			relid = RelOid_pg_group;		else if (strcmp(DatabaseRelationName, relname) == 0)			relid = RelOid_pg_database;		else			relid = newoid();	}	else		relid = newoid();	/*	 * For now, the physical identifier of the relation is the same as the	 * logical identifier.	 */	rnode.tblNode = dbid;	rnode.relNode = relid;	/*	 * build the relcache entry.	 */	rel = RelationBuildLocalRelation(relname,									 relnamespace,									 tupDesc,									 relid, dbid,									 rnode,									 nailme);	/*	 * have the storage manager create the relation's disk file, if	 * wanted.	 */	if (storage_create)		heap_storage_create(rel);	return rel;}voidheap_storage_create(Relation rel){	Assert(rel->rd_fd < 0);	rel->rd_fd = smgrcreate(DEFAULT_SMGR, rel);	Assert(rel->rd_fd >= 0);}/* ---------------------------------------------------------------- *		heap_create_with_catalog		- Create a cataloged relation * *		this is done in 6 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) AddNewRelationTuple() is called to register the *		   relation in pg_class. * *		5) TypeCreate() is called to define a new type corresponding *		   to the new relation. * *		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 or one that uses a	 * standalone composite type.  (Eventually we should probably refuse	 * all references to complex types, but for now there's still some	 * Berkeley-derived code that thinks it can do this...)	 */	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))));	}	else if (att_typtype == 'c')	{		Oid			typrelid = get_typ_typrelid(atttypid);		if (get_rel_relkind(typrelid) == RELKIND_COMPOSITE_TYPE)			ereport(ERROR,					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),					 errmsg("column \"%s\" has composite 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){	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_openr(AttributeRelationName, 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 = RelOid_pg_class;		myself.objectId = new_rel_oid;		myself.objectSubId = i + 1;		referenced.classId = RelOid_pg_type;		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

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?