index.c

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

C
1,784
字号
	/* update the indexes on pg_index */	CatalogUpdateIndexes(pg_index, tuple);	/*	 * close the relation and free the tuple	 */	heap_close(pg_index, RowExclusiveLock);	heap_freetuple(tuple);}/* ---------------------------------------------------------------- *		index_create * * Returns OID of the created index. * ---------------------------------------------------------------- */Oidindex_create(Oid heapRelationId,			 const char *indexRelationName,			 IndexInfo *indexInfo,			 Oid accessMethodObjectId,			 Oid *classObjectId,			 bool primary,			 bool isconstraint,			 bool allow_system_table_mods){	Relation	heapRelation;	Relation	indexRelation;	TupleDesc	indexTupDesc;	bool		shared_relation;	Oid			namespaceId;	Oid			indexoid;	int			i;	/*	 * Only SELECT ... FOR UPDATE are allowed while doing this	 */	heapRelation = heap_open(heapRelationId, ShareLock);	/*	 * The index will be in the same namespace as its parent table, and is	 * shared across databases if and only if the parent is.	 */	namespaceId = RelationGetNamespace(heapRelation);	shared_relation = heapRelation->rd_rel->relisshared;	/*	 * check parameters	 */	if (indexInfo->ii_NumIndexAttrs < 1)		elog(ERROR, "must index at least one column");	if (!allow_system_table_mods &&		IsSystemRelation(heapRelation) &&		IsNormalProcessingMode())		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				 errmsg("user-defined indexes on system catalog tables are not supported")));	/*	 * We cannot allow indexing a shared relation after initdb (because	 * there's no way to make the entry in other databases' pg_class).	 * Unfortunately we can't distinguish initdb from a manually started	 * standalone backend.	However, we can at least prevent this mistake	 * under normal multi-user operation.	 */	if (shared_relation && IsUnderPostmaster)		ereport(ERROR,				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),			   errmsg("shared indexes cannot be created after initdb")));	if (get_relname_relid(indexRelationName, namespaceId))		ereport(ERROR,				(errcode(ERRCODE_DUPLICATE_TABLE),				 errmsg("relation \"%s\" already exists",						indexRelationName)));	/*	 * construct tuple descriptor for index tuples	 */	indexTupDesc = ConstructTupleDescriptor(heapRelation,											indexInfo,											classObjectId);	/*	 * create the index relation's relcache entry and physical disk file.	 * (If we fail further down, it's the smgr's responsibility to remove	 * the disk file again.)	 */	indexRelation = heap_create(indexRelationName,								namespaceId,								indexTupDesc,								shared_relation,								true,								allow_system_table_mods);	/* Fetch the relation OID assigned by heap_create */	indexoid = RelationGetRelid(indexRelation);	/*	 * Obtain exclusive lock on it.  Although no other backends can see it	 * until we commit, this prevents deadlock-risk complaints from lock	 * manager in cases such as CLUSTER.	 */	LockRelation(indexRelation, AccessExclusiveLock);	/*	 * Fill in fields of the index's pg_class entry that are not set	 * correctly by heap_create.	 *	 * XXX should have a cleaner way to create cataloged indexes	 */	indexRelation->rd_rel->relowner = GetUserId();	indexRelation->rd_rel->relam = accessMethodObjectId;	indexRelation->rd_rel->relkind = RELKIND_INDEX;	indexRelation->rd_rel->relhasoids = false;	/*	 * store index's pg_class entry	 */	UpdateRelationRelation(indexRelation);	/*	 * now update the object id's of all the attribute tuple forms in the	 * index relation's tuple descriptor	 */	InitializeAttributeOids(indexRelation,							indexInfo->ii_NumIndexAttrs,							indexoid);	/*	 * append ATTRIBUTE tuples for the index	 */	AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);	/* ----------------	 *	  update pg_index	 *	  (append INDEX tuple)	 *	 *	  Note that this stows away a representation of "predicate".	 *	  (Or, could define a rule to maintain the predicate) --Nels, Feb '92	 * ----------------	 */	UpdateIndexRelation(indexoid, heapRelationId, indexInfo,						classObjectId, primary);	/*	 * Register constraint and dependencies for the index.	 *	 * If the index is from a CONSTRAINT clause, construct a pg_constraint	 * entry.  The index is then linked to the constraint, which in turn	 * is linked to the table.	If it's not a CONSTRAINT, make the	 * dependency directly on the table.	 *	 * We don't need a dependency on the namespace, because there'll be an	 * indirect dependency via our parent table.	 *	 * During bootstrap we can't register any dependencies, and we don't try	 * to make a constraint either.	 */	if (!IsBootstrapProcessingMode())	{		ObjectAddress myself,					referenced;		myself.classId = RelOid_pg_class;		myself.objectId = indexoid;		myself.objectSubId = 0;		if (isconstraint)		{			char		constraintType;			Oid			conOid;			if (primary)				constraintType = CONSTRAINT_PRIMARY;			else if (indexInfo->ii_Unique)				constraintType = CONSTRAINT_UNIQUE;			else			{				elog(ERROR, "constraint must be PRIMARY or UNIQUE");				constraintType = 0;		/* keep compiler quiet */			}			/* Shouldn't have any expressions */			if (indexInfo->ii_Expressions)				elog(ERROR, "constraints can't have index expressions");			conOid = CreateConstraintEntry(indexRelationName,										   namespaceId,										   constraintType,										   false,		/* isDeferrable */										   false,		/* isDeferred */										   heapRelationId,										   indexInfo->ii_KeyAttrNumbers,										   indexInfo->ii_NumIndexAttrs,										   InvalidOid,	/* no domain */										   InvalidOid,	/* no foreign key */										   NULL,										   0,										   ' ',										   ' ',										   ' ',										   InvalidOid,	/* no associated index */										   NULL,		/* no check constraint */										   NULL,										   NULL);			referenced.classId = get_system_catalog_relid(ConstraintRelationName);			referenced.objectId = conOid;			referenced.objectSubId = 0;			recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);		}		else		{			/* Create auto dependencies on simply-referenced columns */			for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)			{				if (indexInfo->ii_KeyAttrNumbers[i] != 0)				{					referenced.classId = RelOid_pg_class;					referenced.objectId = heapRelationId;					referenced.objectSubId = indexInfo->ii_KeyAttrNumbers[i];					recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);				}			}		}		/* Store dependency on operator classes */		referenced.classId = get_system_catalog_relid(OperatorClassRelationName);		for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)		{			referenced.objectId = classObjectId[i];			referenced.objectSubId = 0;			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);		}		/* Store dependencies on anything mentioned in index expressions */		if (indexInfo->ii_Expressions)		{			recordDependencyOnSingleRelExpr(&myself,									  (Node *) indexInfo->ii_Expressions,											heapRelationId,											DEPENDENCY_NORMAL,											DEPENDENCY_AUTO);		}		/* Store dependencies on anything mentioned in predicate */		if (indexInfo->ii_Predicate)		{			recordDependencyOnSingleRelExpr(&myself,										(Node *) indexInfo->ii_Predicate,											heapRelationId,											DEPENDENCY_NORMAL,											DEPENDENCY_AUTO);		}	}	/*	 * Fill in the index strategy structure with information from the	 * catalogs.  First we must advance the command counter so that we	 * will see the newly-entered index catalog tuples.	 */	CommandCounterIncrement();	RelationInitIndexAccessInfo(indexRelation);	/*	 * If this is bootstrap (initdb) time, then we don't actually fill in	 * the index yet.  We'll be creating more indexes and classes later,	 * so we delay filling them in until just before we're done with	 * bootstrapping.  Otherwise, we call the routine that constructs the	 * index.	 *	 * In normal processing mode, the heap and index relations are closed by	 * index_build() --- but we continue to hold the ShareLock on the heap	 * and the exclusive lock on the index that we acquired above, until	 * end of transaction.	 */	if (IsBootstrapProcessingMode())	{		index_register(heapRelationId, indexoid, indexInfo);		/* XXX shouldn't we close the heap and index rels here? */	}	else		index_build(heapRelation, indexRelation, indexInfo);	return indexoid;}/* *		index_drop * * NOTE: this routine should now only be called through performDeletion(), * else associated dependencies won't be cleaned up. */voidindex_drop(Oid indexId){	Oid			heapId;	Relation	userHeapRelation;	Relation	userIndexRelation;	Relation	indexRelation;	HeapTuple	tuple;	int			i;	Assert(OidIsValid(indexId));	/*	 * To drop an index safely, we must grab exclusive lock on its parent	 * table; otherwise there could be other backends using the index!	 * Exclusive lock on the index alone is insufficient because another	 * backend might be in the midst of devising a query plan that will	 * use the index.  The parser and planner take care to hold an	 * appropriate lock on the parent table while working, but having them	 * hold locks on all the indexes too seems overly complex.	We do grab	 * exclusive lock on the index too, just to be safe. Both locks must	 * be held till end of transaction, else other backends will still see	 * this index in pg_index.	 */	heapId = IndexGetRelation(indexId);	userHeapRelation = heap_open(heapId, AccessExclusiveLock);	userIndexRelation = index_open(indexId);	LockRelation(userIndexRelation, AccessExclusiveLock);	/*	 * fix RELATION relation	 */	DeleteRelationTuple(indexId);	/*	 * fix ATTRIBUTE relation	 */	DeleteAttributeTuples(indexId);	/*	 * fix INDEX relation	 */	indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);	tuple = SearchSysCache(INDEXRELID,						   ObjectIdGetDatum(indexId),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "cache lookup failed for index %u", indexId);	simple_heap_delete(indexRelation, &tuple->t_self);	ReleaseSysCache(tuple);	heap_close(indexRelation, RowExclusiveLock);	/*	 * flush buffer cache and physically remove the file	 */	i = FlushRelationBuffers(userIndexRelation, (BlockNumber) 0);	if (i < 0)		elog(ERROR, "FlushRelationBuffers returned %d", i);	smgrunlink(DEFAULT_SMGR, userIndexRelation);	/*	 * We are presently too lazy to attempt to compute the new correct	 * value of relhasindex (the next VACUUM will fix it if necessary). So	 * there is no need to update the pg_class tuple for the owning	 * relation. But we must send out a shared-cache-inval notice on the	 * owning relation to ensure other backends update their relcache	 * lists of indexes.	 */	CacheInvalidateRelcache(heapId);	/*	 * Close rels, but keep locks	 */	index_close(userIndexRelation);	heap_close(userHeapRelation, NoLock);	RelationForgetRelation(indexId);}/* ---------------------------------------------------------------- *						index_build support * ---------------------------------------------------------------- *//* ---------------- *		BuildIndexInfo *			Construct an IndexInfo record for an open index * * IndexInfo stores the information about the index that's needed by * FormIndexDatum, which is used for both index_build() and later insertion * of individual index tuples.	Normally we build an IndexInfo for an index * just once per command, and then use it for (potentially) many tuples. * ---------------- */IndexInfo *BuildIndexInfo(Relation index){	IndexInfo  *ii = makeNode(IndexInfo);	Form_pg_index indexStruct = index->rd_index;	int			i;	int			numKeys;	/* check the number of keys, and copy attr numbers into the IndexInfo */	numKeys = indexStruct->indnatts;	if (numKeys < 1 || numKeys > INDEX_MAX_KEYS)		elog(ERROR, "invalid indnatts %d for index %u",			 numKeys, RelationGetRelid(index));	ii->ii_NumIndexAttrs = numKeys;	for (i = 0; i < numKeys; i++)		ii->ii_KeyAttrNumbers[i] = indexStruct->indkey[i];	/* fetch any expressions needed for expressional indexes */	ii->ii_Expressions = RelationGetIndexExpressions(index);	ii->ii_ExpressionsState = NIL;	/* fetch index predicate if any */	ii->ii_Predicate = RelationGetIndexPredicate(index);	ii->ii_PredicateState = NIL;	/* other info */	ii->ii_Unique = indexStruct->indisunique;	return ii;}/* ---------------- *		FormIndexDatum *			Construct Datum[] and nullv[] arrays for a new index tuple. * *	indexInfo		Info about the index *	heapTuple		Heap tuple for which we must prepare an index entry *	heapDescriptor	tupledesc for heap tuple *	estate			executor state for evaluating any index expressions *	datum			Array of index Datums (output area) *	nullv			Array of is-null indicators (output area) * * When there are no index expressions, estate may be NULL.  Otherwise it * must be supplied, *and* the ecxt_scantuple slot of its per-tuple expr * context must point to the heap tuple passed in. * * For largely historical reasons, we don't actually call index_formtuple()

⌨️ 快捷键说明

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