⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 index.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 4 页
字号:
 * here, we just prepare its input arrays datum[] and nullv[]. * ---------------- */voidFormIndexDatum(IndexInfo *indexInfo,			   HeapTuple heapTuple,			   TupleDesc heapDescriptor,			   EState *estate,			   Datum *datum,			   char *nullv){	List	   *indexprs;	int			i;	if (indexInfo->ii_Expressions != NIL &&		indexInfo->ii_ExpressionsState == NIL)	{		/* First time through, set up expression evaluation state */		indexInfo->ii_ExpressionsState = (List *)			ExecPrepareExpr((Expr *) indexInfo->ii_Expressions,							estate);		/* Check caller has set up context correctly */		Assert(GetPerTupleExprContext(estate)->ecxt_scantuple->val == heapTuple);	}	indexprs = indexInfo->ii_ExpressionsState;	for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)	{		int			keycol = indexInfo->ii_KeyAttrNumbers[i];		Datum		iDatum;		bool		isNull;		if (keycol != 0)		{			/*			 * Plain index column; get the value we need directly from the			 * heap tuple.			 */			iDatum = heap_getattr(heapTuple, keycol, heapDescriptor, &isNull);		}		else		{			/*			 * Index expression --- need to evaluate it.			 */			if (indexprs == NIL)				elog(ERROR, "wrong number of index expressions");			iDatum = ExecEvalExprSwitchContext((ExprState *) lfirst(indexprs),										  GetPerTupleExprContext(estate),											   &isNull,											   NULL);			indexprs = lnext(indexprs);		}		datum[i] = iDatum;		nullv[i] = (isNull) ? 'n' : ' ';	}	if (indexprs != NIL)		elog(ERROR, "wrong number of index expressions");}/* ---------------- *		set relhasindex of relation's pg_class entry * * If isprimary is TRUE, we are defining a primary index, so also set * relhaspkey to TRUE.	Otherwise, leave relhaspkey alone. * * If reltoastidxid is not InvalidOid, also set reltoastidxid to that value. * This is only used for TOAST relations. * * NOTE: an important side-effect of this operation is that an SI invalidation * message is sent out to all backends --- including me --- causing relcache * entries to be flushed or updated with the new hasindex data.  This must * happen even if we find that no change is needed in the pg_class row. * ---------------- */voidsetRelhasindex(Oid relid, bool hasindex, bool isprimary, Oid reltoastidxid){	Relation	pg_class;	HeapTuple	tuple;	Form_pg_class classtuple;	bool		dirty = false;	HeapScanDesc pg_class_scan = NULL;	/*	 * Find the tuple to update in pg_class.  In bootstrap mode we can't	 * use heap_update, so cheat and overwrite the tuple in-place.  In	 * normal processing, make a copy to scribble on.	 */	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);	if (!IsBootstrapProcessingMode())	{		tuple = SearchSysCacheCopy(RELOID,								   ObjectIdGetDatum(relid),								   0, 0, 0);	}	else	{		ScanKeyData key[1];		ScanKeyEntryInitialize(&key[0], 0,							   ObjectIdAttributeNumber,							   F_OIDEQ,							   ObjectIdGetDatum(relid));		pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key);		tuple = heap_getnext(pg_class_scan, ForwardScanDirection);	}	if (!HeapTupleIsValid(tuple))		elog(ERROR, "could not find tuple for relation %u", relid);	classtuple = (Form_pg_class) GETSTRUCT(tuple);	/* Apply required updates */	if (pg_class_scan)		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);	if (classtuple->relhasindex != hasindex)	{		classtuple->relhasindex = hasindex;		dirty = true;	}	if (isprimary)	{		if (!classtuple->relhaspkey)		{			classtuple->relhaspkey = true;			dirty = true;		}	}	if (OidIsValid(reltoastidxid))	{		Assert(classtuple->relkind == RELKIND_TOASTVALUE);		if (classtuple->reltoastidxid != reltoastidxid)		{			classtuple->reltoastidxid = reltoastidxid;			dirty = true;		}	}	if (pg_class_scan)		LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);	if (pg_class_scan)	{		/* Write the modified tuple in-place */		WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);		/* Send out shared cache inval if necessary */		if (!IsBootstrapProcessingMode())			CacheInvalidateHeapTuple(pg_class, tuple);		BufferSync();	}	else if (dirty)	{		simple_heap_update(pg_class, &tuple->t_self, tuple);		/* Keep the catalog indexes up to date */		CatalogUpdateIndexes(pg_class, tuple);	}	else	{		/* no need to change tuple, but force relcache rebuild anyway */		CacheInvalidateRelcache(relid);	}	if (!pg_class_scan)		heap_freetuple(tuple);	else		heap_endscan(pg_class_scan);	heap_close(pg_class, RowExclusiveLock);}/* * setNewRelfilenode		- assign a new relfilenode value to the relation * * Caller must already hold exclusive lock on the relation. */voidsetNewRelfilenode(Relation relation){	Oid			newrelfilenode;	Relation	pg_class;	HeapTuple	tuple;	Form_pg_class rd_rel;	RelationData workrel;	/* Can't change relfilenode for nailed tables (indexes ok though) */	Assert(!relation->rd_isnailed ||		   relation->rd_rel->relkind == RELKIND_INDEX);	/* Can't change for shared tables or indexes */	Assert(!relation->rd_rel->relisshared);	/* Allocate a new relfilenode */	newrelfilenode = newoid();	/*	 * Find the pg_class tuple for the given relation.  This is not used	 * during bootstrap, so okay to use heap_update always.	 */	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);	tuple = SearchSysCacheCopy(RELOID,							   ObjectIdGetDatum(RelationGetRelid(relation)),							   0, 0, 0);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "could not find tuple for relation %u",			 RelationGetRelid(relation));	rd_rel = (Form_pg_class) GETSTRUCT(tuple);	/* create another storage file. Is it a little ugly ? */	/* NOTE: any conflict in relfilenode value will be caught here */	memcpy((char *) &workrel, relation, sizeof(RelationData));	workrel.rd_fd = -1;	workrel.rd_node.relNode = newrelfilenode;	heap_storage_create(&workrel);	smgrclose(DEFAULT_SMGR, &workrel);	/* schedule unlinking old relfilenode */	smgrunlink(DEFAULT_SMGR, relation);	/* update the pg_class row */	rd_rel->relfilenode = newrelfilenode;	simple_heap_update(pg_class, &tuple->t_self, tuple);	CatalogUpdateIndexes(pg_class, tuple);	heap_freetuple(tuple);	heap_close(pg_class, RowExclusiveLock);	/* Make sure the relfilenode change is visible */	CommandCounterIncrement();}/* ---------------- *		UpdateStats * * Update pg_class' relpages and reltuples statistics for the given relation * (which can be either a table or an index).  Note that this is not used * in the context of VACUUM. * ---------------- */voidUpdateStats(Oid relid, double reltuples){	Relation	whichRel;	Relation	pg_class;	HeapTuple	tuple;	BlockNumber relpages;	Form_pg_class rd_rel;	HeapScanDesc pg_class_scan = NULL;	bool		in_place_upd;	/*	 * This routine handles updates for both the heap and index relation	 * statistics.	In order to guarantee that we're able to *see* the	 * index relation tuple, we bump the command counter id here.  The	 * index relation tuple was created in the current transaction.	 */	CommandCounterIncrement();	/*	 * CommandCounterIncrement() flushes invalid cache entries, including	 * those for the heap and index relations for which we're updating	 * statistics.	Now that the cache is flushed, it's safe to open the	 * relation again.	We need the relation open in order to figure out	 * how many blocks it contains.	 */	/*	 * Grabbing lock here is probably redundant ...	 */	whichRel = relation_open(relid, ShareLock);	/*	 * Find the tuple to update in pg_class.  Normally we make a copy of	 * the tuple using the syscache, modify it, and apply heap_update.	 * But in bootstrap mode we can't use heap_update, so we cheat and	 * overwrite the tuple in-place.	 *	 * We also must cheat if reindexing pg_class itself, because the	 * target index may presently not be part of the set of indexes that	 * CatalogUpdateIndexes would update (see reindex_relation).  In this	 * case the stats updates will not be WAL-logged and so could be lost	 * in a crash.  This seems OK considering VACUUM does the same thing.	 */	pg_class = heap_openr(RelationRelationName, RowExclusiveLock);	in_place_upd = IsBootstrapProcessingMode() ||		ReindexIsProcessingHeap(RelationGetRelid(pg_class));	if (!in_place_upd)	{		tuple = SearchSysCacheCopy(RELOID,								   ObjectIdGetDatum(relid),								   0, 0, 0);	}	else	{		ScanKeyData key[1];		ScanKeyEntryInitialize(&key[0], 0,							   ObjectIdAttributeNumber,							   F_OIDEQ,							   ObjectIdGetDatum(relid));		pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key);		tuple = heap_getnext(pg_class_scan, ForwardScanDirection);	}	if (!HeapTupleIsValid(tuple))		elog(ERROR, "could not find tuple for relation %u", relid);	rd_rel = (Form_pg_class) GETSTRUCT(tuple);	/*	 * Figure values to insert.	 *	 * If we found zero tuples in the scan, do NOT believe it; instead put a	 * bogus estimate into the statistics fields.  Otherwise, the common	 * pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table	 * with zero size statistics until a VACUUM is done.  The optimizer	 * will generate very bad plans if the stats claim the table is empty	 * when it is actually sizable.  See also CREATE TABLE in heap.c.	 *	 * Note: this path is also taken during bootstrap, because bootstrap.c	 * passes reltuples = 0 after loading a table.	We have to estimate	 * some number for reltuples based on the actual number of pages.	 */	relpages = RelationGetNumberOfBlocks(whichRel);	if (reltuples == 0)	{		if (relpages == 0)		{			/* Bogus defaults for a virgin table, same as heap.c */			reltuples = 1000;			relpages = 10;		}		else if (whichRel->rd_rel->relkind == RELKIND_INDEX && relpages <= 2)		{			/* Empty index, leave bogus defaults in place */			reltuples = 1000;		}		else			reltuples = ((double) relpages) * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);	}	/*	 * Update statistics in pg_class, if they changed.	(Avoiding an	 * unnecessary update is not just a tiny performance improvement; it	 * also reduces the window wherein concurrent CREATE INDEX commands	 * may conflict.)	 */	if (rd_rel->relpages != (int32) relpages ||		rd_rel->reltuples != (float4) reltuples)	{		if (in_place_upd)		{			/* Bootstrap or reindex case: overwrite fields in place. */			LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);			rd_rel->relpages = (int32) relpages;			rd_rel->reltuples = (float4) reltuples;			LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK);			WriteNoReleaseBuffer(pg_class_scan->rs_cbuf);			if (!IsBootstrapProcessingMode())				CacheInvalidateHeapTuple(pg_class, tuple);		}		else		{			/* During normal processing, must work harder. */			rd_rel->relpages = (int32) relpages;			rd_rel->reltuples = (float4) reltuples;			simple_heap_update(pg_class, &tuple->t_self, tuple);			CatalogUpdateIndexes(pg_class, tuple);		}	}	if (!pg_class_scan)		heap_freetuple(tuple);	else		heap_endscan(pg_class_scan);	/*	 * We shouldn't have to do this, but we do...  Modify the reldesc in	 * place with the new values so that the cache contains the latest	 * copy.  (XXX is this really still necessary?	The relcache will get	 * fixed at next CommandCounterIncrement, so why bother here?)	 */	whichRel->rd_rel->relpages = (int32) relpages;	whichRel->rd_rel->reltuples = (float4) reltuples;	heap_close(pg_class, RowExclusiveLock);	relation_close(whichRel, NoLock);}/* * index_build - invoke access-method-specific index build procedure */voidindex_build(Relation heapRelation,			Relation indexRelation,			IndexInfo *indexInfo){	RegProcedure procedure;	/*	 * sanity checks	 */	Assert(RelationIsValid(indexRelation));	Assert(PointerIsValid(indexRelation->rd_am));	procedure = indexRelation->rd_am->ambuild;	Assert(RegProcedureIsValid(procedure));	/*	 * Call the access method's build procedure	 */	OidFunctionCall3(procedure,					 PointerGetDatum(heapRelation),					 PointerGetDatum(indexRelation),					 PointerGetDatum(indexInfo));}/* * IndexBuildHeapScan - scan the heap relation to find tuples to be indexed * * This is called back from an access-method-specific index build procedure * after the AM has done whatever setup it needs.  The parent heap relation * is scanned to find tuples that should be entered into the index.  Each * such tuple is passed to the AM's callback routine, which does the right * things to add it to the new index.  After we return, the AM's index * build procedure does whatever cleanup is needed; in particular, it should * close the heap and index relations. * * The total count of heap tuples is returned.	This is for updating pg_class * statistics.	(It's annoying not to be able to do that here, but we can't * do it until after the relation is closed.)  Note that the index AM itself * must keep track of the number of index tuples; we don't do so here because * the AM might reject some of the tuples for its own reasons, such as being

⌨️ 快捷键说明

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