heap.c

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

C
2,069
字号
	 * 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);				/* Fill in the correct relation OID in the copied tuple */				attStruct = (Form_pg_attribute) GETSTRUCT(tup);				attStruct->attrelid = new_rel_oid;				/*				 * Unneeded since they should be OK in the constant data				 * anyway				 */				/* attStruct->attstattarget = 0; */				/* attStruct->attcacheoff = -1; */				simple_heap_insert(rel, tup);				CatalogIndexInsert(indstate, tup);				heap_freetuple(tup);			}			dpp++;		}	}	/*	 * clean up	 */	CatalogCloseIndexes(indstate);	heap_close(rel, RowExclusiveLock);}/* -------------------------------- *		AddNewRelationTuple * *		this registers the new relation in the catalogs by *		adding a tuple to pg_class. * -------------------------------- */static voidAddNewRelationTuple(Relation pg_class_desc,					Relation new_rel_desc,					Oid new_rel_oid,					Oid new_type_oid,					char relkind){	Form_pg_class new_rel_reltup;	HeapTuple	tup;	/*	 * first we update some of the information in our uncataloged	 * relation's relation descriptor.	 */	new_rel_reltup = new_rel_desc->rd_rel;	/*	 * Here we insert bogus estimates of the size of the new relation. In	 * reality, of course, the new relation has 0 tuples and pages, and if	 * we were tracking these statistics accurately then we'd set the	 * fields that way.  But at present the stats will be updated only by	 * VACUUM or CREATE INDEX, and the user might insert a lot of tuples	 * before he gets around to doing either of those.	So, instead of	 * saying the relation is empty, we insert guesstimates.  The point is	 * to keep the optimizer from making really stupid choices on	 * never-yet-vacuumed tables; so the estimates need only be large	 * enough to discourage the optimizer from using nested-loop plans.	 * With this hack, nested-loop plans will be preferred only after the	 * table has been proven to be small by VACUUM or CREATE INDEX.	 * Maintaining the stats on-the-fly would solve the problem more	 * cleanly, but the overhead of that would likely cost more than it'd	 * save. (NOTE: CREATE INDEX inserts the same bogus estimates if it	 * finds the relation has 0 rows and pages. See index.c.)	 */	switch (relkind)	{		case RELKIND_RELATION:		case RELKIND_INDEX:		case RELKIND_TOASTVALUE:			new_rel_reltup->relpages = 10;		/* bogus estimates */			new_rel_reltup->reltuples = 1000;			break;		case RELKIND_SEQUENCE:			new_rel_reltup->relpages = 1;			new_rel_reltup->reltuples = 1;			break;		default:				/* views, etc */			new_rel_reltup->relpages = 0;			new_rel_reltup->reltuples = 0;			break;	}	new_rel_reltup->relowner = GetUserId();	new_rel_reltup->reltype = new_type_oid;	new_rel_reltup->relkind = relkind;	/* ----------------	 *	now form a tuple to add to pg_class	 *	XXX Natts_pg_class_fixed is a hack - see pg_class.h	 * ----------------	 */	tup = heap_addheader(Natts_pg_class_fixed,						 true,						 CLASS_TUPLE_SIZE,						 (void *) new_rel_reltup);	/* force tuple to have the desired OID */	HeapTupleSetOid(tup, new_rel_oid);	/*	 * finally insert the new tuple, update the indexes, and clean up.	 */	simple_heap_insert(pg_class_desc, tup);	CatalogUpdateIndexes(pg_class_desc, tup);	heap_freetuple(tup);}/* -------------------------------- *		AddNewRelationType - * *		define a complex type corresponding to the new relation * -------------------------------- */static voidAddNewRelationType(const char *typeName,				   Oid typeNamespace,				   Oid new_rel_oid,				   char new_rel_kind,				   Oid new_type_oid){	/*	 * We set the I/O procedures of a complex type to record_in and	 * record_out, so that a user will get an error message not a weird	 * number if he tries to SELECT a complex type.	 *	 * OLD and probably obsolete comments:	 *	 * The sizes are set to oid size because it makes implementing sets MUCH	 * easier, and no one (we hope) uses these fields to figure out how	 * much space to allocate for the type. An oid is the type used for a	 * set definition.	When a user requests a set, what they actually get	 * is the oid of a tuple in the pg_proc catalog, so the size of the	 * "set" is the size of an oid. Similarly, byval being true makes sets	 * much easier, and it isn't used by anything else.	 */	TypeCreate(typeName,		/* type name */			   typeNamespace,	/* type namespace */			   new_type_oid,	/* preassigned oid for type */			   new_rel_oid,		/* relation oid */			   new_rel_kind,	/* relation kind */			   sizeof(Oid),		/* internal size */			   'c',				/* type-type (complex) */			   ',',				/* default array delimiter */			   F_RECORD_IN,		/* input procedure */			   F_RECORD_OUT,	/* output procedure */			   F_RECORD_RECV,	/* receive procedure */			   F_RECORD_SEND,	/* send procedure */			   InvalidOid,		/* array element type - irrelevant */			   InvalidOid,		/* domain base type - irrelevant */			   NULL,			/* default type value - none */			   NULL,			/* default type binary representation */			   true,			/* passed by value */			   'i',				/* default alignment - same as for OID */			   'p',				/* Not TOASTable */			   -1,				/* typmod */			   0,				/* array dimensions for typBaseType */			   false);			/* Type NOT NULL */}/* -------------------------------- *		heap_create_with_catalog * *		creates a new cataloged relation.  see comments above. * -------------------------------- */Oidheap_create_with_catalog(const char *relname,						 Oid relnamespace,						 TupleDesc tupdesc,						 char relkind,						 bool shared_relation,						 OnCommitAction oncommit,						 bool allow_system_table_mods){	Relation	pg_class_desc;	Relation	new_rel_desc;	Oid			new_rel_oid;	Oid			new_type_oid;	/*	 * sanity checks	 */	Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode());	CheckAttributeNamesTypes(tupdesc, relkind);	if (get_relname_relid(relname, relnamespace))		ereport(ERROR,				(errcode(ERRCODE_DUPLICATE_TABLE),				 errmsg("relation \"%s\" already exists", relname)));	/*	 * Create the relcache entry (mostly dummy at this point) and the	 * physical disk file.	(If we fail further down, it's the smgr's	 * responsibility to remove the disk file again.)	 *	 * NB: create a physical file only if it's not a view or type relation.	 */	new_rel_desc = heap_create(relname,							   relnamespace,							   tupdesc,							   shared_relation,							   (relkind != RELKIND_VIEW &&								relkind != RELKIND_COMPOSITE_TYPE),							   allow_system_table_mods);	/* Fetch the relation OID assigned by heap_create */	new_rel_oid = RelationGetRelid(new_rel_desc);	/* Assign an OID for the relation's tuple type */	new_type_oid = newoid();	/*	 * now create an entry in pg_class for the relation.	 *	 * NOTE: we could get a unique-index failure here, in case someone else	 * is creating the same relation name in parallel but hadn't committed	 * yet when we checked for a duplicate name above.	 */	pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock);	AddNewRelationTuple(pg_class_desc,						new_rel_desc,						new_rel_oid,						new_type_oid,						relkind);	/*	 * since defining a relation also defines a complex type, we add a new	 * system type corresponding to the new relation.	 *	 * NOTE: we could get a unique-index failure here, in case the same name	 * has already been used for a type.	 */	AddNewRelationType(relname,					   relnamespace,					   new_rel_oid,					   relkind,					   new_type_oid);	/*	 * now add tuples to pg_attribute for the attributes in our new	 * relation.	 */	AddNewAttributeTuples(new_rel_oid, new_rel_desc->rd_att, relkind);	/*	 * make a dependency link to force the relation to be deleted if its	 * namespace is.  Skip this in bootstrap mode, since we don't make	 * dependencies while bootstrapping.	 */	if (!IsBootstrapProcessingMode())	{		ObjectAddress myself,					referenced;		myself.classId = RelOid_pg_class;		myself.objectId = new_rel_oid;		myself.objectSubId = 0;		referenced.classId = get_system_catalog_relid(NamespaceRelationName);		referenced.objectId = relnamespace;		referenced.objectSubId = 0;		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);	}	/*	 * store constraints and defaults passed in the tupdesc, if any.	 *	 * NB: this may do a CommandCounterIncrement and rebuild the relcache	 * entry, so the relation must be valid and self-consistent at this	 * point. In particular, there are not yet constraints and defaults	 * anywhere.	 */	StoreConstraints(new_rel_desc, tupdesc);	/*	 * If there's a special on-commit action, remember it	 */	if (oncommit != ONCOMMIT_NOOP)		register_on_commit_action(new_rel_oid, oncommit);	/*	 * ok, the relation has been cataloged, so close our relations and	 * return the oid of the newly created relation.	 */	heap_close(new_rel_desc, NoLock);	/* do not unlock till end of xact */	heap_close(pg_class_desc, RowExclusiveLock);	return new_rel_oid;}/* *		RelationRemoveInheritance * * Formerly, this routine checked for child relations and aborted the * deletion if any were found.	Now we rely on the dependency mechanism * to check for or delete child relations.	By the time we get here, * there are no children and we need only remove any pg_inherits rows * linking this relation to its parent(s). */static voidRelationRemoveInheritance(Relation relation){	Relation	catalogRelation;	SysScanDesc scan;	ScanKeyData key;	HeapTuple	tuple;	catalogRelation = heap_openr(InheritsRelationName, RowExclusiveLock);	ScanKeyEntryInitialize(&key, 0x0,						   Anum_pg_inherits_inhrelid, F_OIDEQ,						   ObjectIdGetDatum(RelationGetRelid(relation)));	scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndex, true,							  SnapshotNow, 1, &key);	while (HeapTupleIsValid(tuple = systable_getnext(scan)))		simple_heap_delete(catalogRelation, &tuple->t_self);	systable_endscan(scan);	heap_close(catalogRelation, RowExclusiveLock);}/* *		DeleteRelationTuple * * Remove pg_class row for the given relid. * * Note: this is shared by relation deletion and index deletion.  It's * not intended for use anyplace else. */voidDeleteRelationTuple(Oid relid){	Relation	pg_class_desc;	HeapTuple	tup;	/* Grab an appropriate lock on the pg_class relation */	pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock);	tup = SearchSysCache(RELOID,						 ObjectIdGetDatum(relid),						 0, 0, 0);	if (!HeapTupleIsValid(tup))		elog(ERROR, "cache lookup failed for relation %u", relid);	/* delete the relation tuple from pg_class, and finish up */	simple_heap_delete(pg_class_desc, &tup->t_self);	ReleaseSysCache(tup);	heap_close(pg_class_desc, RowExclusiveLock);}/* *		DeleteAttributeTuples * * Remove pg_attribute rows for the given relid. * * Note: this is shared by relation deletion and index deletion.  It's * not intended for use anyplace else. */voidDeleteAttributeTuples(Oid relid){	Relation	attrel;	SysScanDesc scan;	ScanKeyData key[1];	HeapTuple	atttup;	/* Grab an appropriate lock on the pg_attribute relation */	attrel = heap_openr(AttributeRelationName, RowExclusiveLock);	/* Use the index to scan only attributes of the target relation */	ScanKeyEntryInitialize(&key[0], 0x0,						   Anum_pg_attribute_attrelid, F_OIDEQ,						   ObjectIdGetDatum(relid));	scan = systable_beginscan(attrel, AttributeRelidNumIndex, true,							  SnapshotNow, 1, key);	/* Delete all the matching tuples */	while ((atttup = systable_getnext(scan)) != NULL)		simple_heap_delete(attrel, &atttup->t_self);	/* Clean up after the scan */	systable_endscan(scan);	heap_close(attrel, RowExclusiveLock);}/* *		RemoveAttributeById * * This is the guts of ALTER TABLE DROP COLUMN: actually mark the attribute * deleted in pg_attribute.  We also remove pg_statistic entries for it. * (Everything else needed, such as getting rid of any pg_attrdef entry, * is handled by dependency.c.) */voidRemoveAttributeById(Oid relid, AttrNumber attnum){	Relation	rel;	Relation	attr_rel;	HeapTuple	tuple;	Form_pg_attribute attStruct;	char		newattname[NAMEDATALEN];	/*	 * Grab an exclusive lock on the target table, which we will NOT	 * release until end of transaction.  (In the simple case where we are	 * directly dropping this column, AlterTableDropColumn already did	 * this ... but when cascading from a drop of some other object, we	 * may not have any lock.)	 */	rel = relation_open(relid, AccessExclusiveLock);	attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);	tuple = SearchSysCacheCopy(ATTNUM,							   ObjectIdGetDatum(relid),							   Int16GetDatum(attnum),							   0, 0);	if (!HeapTupleIsValid(tuple))		/* shouldn't happen */		elog(ERROR, "cache lookup failed for attribute %d of relation %u",			 attnum, relid);	attStruct = (Form_pg_attribute) GETSTRUCT(tuple);	/* Mark the attribute as dropped */	attStruct->attisdropped = true;	/*	 * Set the type OID to invalid.  A dropped attribute's type link	 * cannot be relied on (once the attribute is dropped, the type might	 * be too). Fortunately we do not need the type row --- the only	 * really essential information is the type's typlen and typalign,	 * which are preserved in the attribute's attlen and attalign.  We set	 * atttypid to zero here as a means of catching code that incorrectly	 * expects it to be valid.	 */	attStruct->atttypid = InvalidOid;	/* Remove any NOT NULL constraint the column may have */	attStruct->attnotnull = false;	/* We don't want to keep stats for it anymore */	attStruct->attstattarget = 0;	/* Change the column name to something that isn't likely to conflict */	snprintf(newattname, sizeof(newattname),			 "........pg.dropped.%d........", attnum);	namestrcpy(&(attStruct->attname), newattname);	simple_heap_update(attr_rel, &tuple->t_self, tuple);	/* keep the system catalog indexes current */	CatalogUpdateIndexes(attr_rel, tuple);	/*	 * Because updating the pg_attribute row will trigger a relcache flush	 * for the target relation, we need not do anything else to notify	 * other backends of the change.	 */	heap_close(attr_rel, RowExclusiveLock);	RemoveStatistics(rel, attnum);	relation_close(rel, NoLock);}/* *		RemoveAttrDefault * * If the specified relation/attribute has a default, remove it. * (If no default, raise error if complain is true, else return quietly.) */voidRemoveAttrDefault(Oid relid, AttrNumber attnum,				  DropBehavior behavior, bool complain){	Relation	attrdef_rel;	ScanKeyData scankeys[2];	SysScanDesc scan;	HeapTuple	tuple;	bool		found = false;	attrdef_rel = heap_openr(AttrDefaultRelationName, RowExclusiveLock);	ScanKeyEntryInitialize(&scankeys[0], 0x0,						   Anum_pg_attrdef_adrelid, F_OIDEQ,

⌨️ 快捷键说明

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