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

📄 nodeindexscan.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * nodeIndexscan.c *	  Routines to support indexes and indexed scans of relations * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.36 1999/05/25 16:08:43 momjian Exp $ * *------------------------------------------------------------------------- *//* * INTERFACE ROUTINES *		ExecInsertIndexTuples	inserts tuples into indices on result relation * *		ExecIndexScan			scans a relation using indices *		ExecIndexNext			using index to retrieve next tuple *		ExecInitIndexScan		creates and initializes state info. *		ExecIndexReScan			rescans the indexed relation. *		ExecEndIndexScan		releases all storage. *		ExecIndexMarkPos		marks scan position. *		ExecIndexRestrPos		restores scan position. * *	 NOTES *		the code supporting ExecInsertIndexTuples should be *		collected and merged with the genam stuff. * */#include "postgres.h"#include "executor/executor.h"#include "executor/execdebug.h"#include "executor/nodeIndexscan.h"#include "optimizer/clauses.h"	/* for get_op, get_leftop, get_rightop */#include "parser/parsetree.h"	/* for rt_fetch() */#include "access/skey.h"#include "access/heapam.h"#include "access/genam.h"#include "utils/palloc.h"#include "utils/mcxt.h"#include "catalog/index.h"#include "storage/bufmgr.h"#include "storage/lmgr.h"#include "nodes/nodeFuncs.h"/* ---------------- *		Misc stuff to move to executor.h soon -cim 6/5/90 * ---------------- */#define NO_OP			0#define LEFT_OP			1#define RIGHT_OP		2static TupleTableSlot *IndexNext(IndexScan *node);/* ---------------------------------------------------------------- *		IndexNext * *		Retrieve a tuple from the IndexScan node's currentRelation *		using the indices in the IndexScanState information. * *		note: the old code mentions 'Primary indices'.	to my knowledge *		we only support a single secondary index. -cim 9/11/89 * * old comments: *		retrieve a tuple from relation using the indices given. *		The indices are used in the order they appear in 'indices'. *		The indices may be primary or secondary indices: *		  * primary index --	scan the relation 'relID' using keys supplied. *		  * secondary index --	scan the index relation to get the 'tid' for *								a tuple in the relation 'relID'. *		If the current index(pointed by 'indexPtr') fails to return a *		tuple, the next index in the indices is used. * *		  bug fix so that it should retrieve on a null scan key. * ---------------------------------------------------------------- */static TupleTableSlot *IndexNext(IndexScan *node){	EState	   *estate;	CommonScanState *scanstate;	IndexScanState *indexstate;	ScanDirection direction;	Snapshot	snapshot;	IndexScanDescPtr scanDescs;	IndexScanDesc scandesc;	Relation	heapRelation;	RetrieveIndexResult result;	HeapTuple	tuple;	TupleTableSlot *slot;	Buffer		buffer = InvalidBuffer;	int			numIndices;	bool		bBackward;	int			indexNumber;	/* ----------------	 *	extract necessary information from index scan node	 * ----------------	 */	estate = node->scan.plan.state;	direction = estate->es_direction;	snapshot = estate->es_snapshot;	scanstate = node->scan.scanstate;	indexstate = node->indxstate;	scanDescs = indexstate->iss_ScanDescs;	heapRelation = scanstate->css_currentRelation;	numIndices = indexstate->iss_NumIndices;	slot = scanstate->css_ScanTupleSlot;	/*	 * Check if we are evaluating PlanQual for tuple of this relation.	 * Additional checking is not good, but no other way for now. We could	 * introduce new nodes for this case and handle IndexScan --> NewNode	 * switching in Init/ReScan plan...	 */	if (estate->es_evTuple != NULL &&		estate->es_evTuple[node->scan.scanrelid - 1] != NULL)	{		int			iptr;		slot->ttc_buffer = InvalidBuffer;		slot->ttc_shouldFree = false;		if (estate->es_evTupleNull[node->scan.scanrelid - 1])		{			slot->val = NULL;	/* must not free tuple! */			return (slot);		}		slot->val = estate->es_evTuple[node->scan.scanrelid - 1];		for (iptr = 0; iptr < numIndices; iptr++)		{			scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot;			if (ExecQual(nth(iptr, node->indxqualorig),						 scanstate->cstate.cs_ExprContext))				break;		}		if (iptr == numIndices) /* would not be returned by indices */			slot->val = NULL;		/* Flag for the next call that no more tuples */		estate->es_evTupleNull[node->scan.scanrelid - 1] = true;		return (slot);	}	tuple = &(indexstate->iss_htup);	/* ----------------	 *	ok, now that we have what we need, fetch an index tuple.	 *	if scanning this index succeeded then return the	 *	appropriate heap tuple.. else return NULL.	 * ----------------	 */	bBackward = ScanDirectionIsBackward(direction);	if (bBackward)	{		indexNumber = numIndices - indexstate->iss_IndexPtr - 1;		if (indexNumber < 0)		{			indexNumber = 0;			indexstate->iss_IndexPtr = numIndices - 1;		}	}	else	{		if ((indexNumber = indexstate->iss_IndexPtr) < 0)		{			indexNumber = 0;			indexstate->iss_IndexPtr = 0;		}	}	while (indexNumber < numIndices)	{		scandesc = scanDescs[indexstate->iss_IndexPtr];		while ((result = index_getnext(scandesc, direction)) != NULL)		{			tuple->t_self = result->heap_iptr;			heap_fetch(heapRelation, snapshot, tuple, &buffer);			pfree(result);			if (tuple->t_data != NULL)			{				bool		prev_matches = false;				int			prev_index;				/* ----------------				 *	store the scanned tuple in the scan tuple slot of				 *	the scan state.  Eventually we will only do this and not				 *	return a tuple.  Note: we pass 'false' because tuples				 *	returned by amgetnext are pointers onto disk pages and				 *	were not created with palloc() and so should not be pfree()'d.				 * ----------------				 */				ExecStoreTuple(tuple,	/* tuple to store */							   slot,	/* slot to store in */							   buffer,	/* buffer associated with tuple  */							   false);	/* don't pfree */				/*				 * We must check to see if the current tuple would have				 * been matched by an earlier index, so we don't double				 * report it. We do this by passing the tuple through				 * ExecQual and look for failure with all previous				 * qualifications.				 */				for (prev_index = 0; prev_index < indexstate->iss_IndexPtr;					 prev_index++)				{					scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot;					if (ExecQual(nth(prev_index, node->indxqualorig),								 scanstate->cstate.cs_ExprContext))					{						prev_matches = true;						break;					}				}				if (!prev_matches)					return slot;				else					ExecClearTuple(slot);			}			if (BufferIsValid(buffer))				ReleaseBuffer(buffer);		}		if (indexNumber < numIndices)		{			indexNumber++;			if (bBackward)				indexstate->iss_IndexPtr--;			else				indexstate->iss_IndexPtr++;		}	}	/* ----------------	 *	if we get here it means the index scan failed so we	 *	are at the end of the scan..	 * ----------------	 */	return ExecClearTuple(slot);}/* ---------------------------------------------------------------- *		ExecIndexScan(node) * * old comments: *		Scans the relation using primary or secondary indices and returns *		   the next qualifying tuple in the direction specified. *		It calls ExecScan() and passes it the access methods which returns *		the next tuple using the indices. * *		Conditions: *		  -- the "cursor" maintained by the AMI is positioned at the tuple *			 returned previously. * *		Initial States: *		  -- the relation indicated is opened for scanning so that the *			 "cursor" is positioned before the first qualifying tuple. *		  -- all index realtions are opened for scanning. *		  -- indexPtr points to the first index. *		  -- state variable ruleFlag = nil. * ---------------------------------------------------------------- */TupleTableSlot *ExecIndexScan(IndexScan *node){	/* ----------------	 *	use IndexNext as access method	 * ----------------	 */	return ExecScan(&node->scan, IndexNext);}/* ---------------------------------------------------------------- *		ExecIndexReScan(node) * *		Recalculates the value of the scan keys whose value depends on *		information known at runtime and rescans the indexed relation. *		Updating the scan key was formerly done separately in *		ExecUpdateIndexScanKeys. Integrating it into ReScan *		makes rescans of indices and *		relations/general streams more uniform. * * ---------------------------------------------------------------- */voidExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent){	EState	   *estate;	IndexScanState *indexstate;	ScanDirection direction;	IndexScanDescPtr scanDescs;	ScanKey    *scanKeys;	IndexScanDesc scan;	ScanKey		skey;	int			numIndices;	int			i;	Pointer    *runtimeKeyInfo;	int		   *numScanKeys;	List	   *indxqual;	List	   *qual;	int			n_keys;	ScanKey		scan_keys;	int		   *run_keys;	int			j;	Expr	   *clause;	Node	   *scanexpr;	Datum		scanvalue;	bool		isNull;	bool		isDone;	indexstate = node->indxstate;	estate = node->scan.plan.state;	direction = estate->es_direction;	numIndices = indexstate->iss_NumIndices;	scanDescs = indexstate->iss_ScanDescs;	scanKeys = indexstate->iss_ScanKeys;	runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;	indxqual = node->indxqual;	numScanKeys = indexstate->iss_NumScanKeys;	indexstate->iss_IndexPtr = -1;	/* If this is re-scanning of PlanQual ... */	if (estate->es_evTuple != NULL &&		estate->es_evTuple[node->scan.scanrelid - 1] != NULL)	{		estate->es_evTupleNull[node->scan.scanrelid - 1] = false;		return;	}	/* it's possible in subselects */	if (exprCtxt == NULL)		exprCtxt = node->scan.scanstate->cstate.cs_ExprContext;	node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple = exprCtxt->ecxt_outertuple;	/*	 * get the index qualifications and recalculate the appropriate values	 */	for (i = 0; i < numIndices; i++)	{		qual = nth(i, indxqual);		n_keys = numScanKeys[i];		scan_keys = (ScanKey) scanKeys[i];		if (runtimeKeyInfo)		{			run_keys = (int *) runtimeKeyInfo[i];			for (j = 0; j < n_keys; j++)			{				/*				 * If we have a run-time key, then extract the run-time				 * expression and evaluate it with respect to the current				 * outer tuple.  We then stick the result into the scan				 * key.				 */				if (run_keys[j] != NO_OP)				{					clause = nth(j, qual);					scanexpr = (run_keys[j] == RIGHT_OP) ?						(Node *) get_rightop(clause) : (Node *) get_leftop(clause);					/*					 * pass in isDone but ignore it.  We don't iterate in					 * quals					 */					scanvalue = (Datum)						ExecEvalExpr(scanexpr, exprCtxt, &isNull, &isDone);					scan_keys[j].sk_argument = scanvalue;					if (isNull)						scan_keys[j].sk_flags |= SK_ISNULL;					else						scan_keys[j].sk_flags &= ~SK_ISNULL;				}			}		}		scan = scanDescs[i];		skey = scanKeys[i];		index_rescan(scan, direction, skey);	}	/* ----------------	 *	perhaps return something meaningful	 * ----------------	 */	return;}/* ---------------------------------------------------------------- *		ExecEndIndexScan * * old comments *		Releases any storage allocated through C routines. *		Returns nothing. * ---------------------------------------------------------------- */voidExecEndIndexScan(IndexScan *node){	CommonScanState *scanstate;	IndexScanState *indexstate;	Pointer    *runtimeKeyInfo;	ScanKey    *scanKeys;	List	   *indxqual;	int		   *numScanKeys;	int			numIndices;	int			i;	scanstate = node->scan.scanstate;	indexstate = node->indxstate;	indxqual = node->indxqual;	runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;	/* ----------------	 *	extract information from the node	 * ----------------	 */	numIndices = indexstate->iss_NumIndices;	scanKeys = indexstate->iss_ScanKeys;	numScanKeys = indexstate->iss_NumScanKeys;	/* ----------------	 *	Free the projection info and the scan attribute info	 *	 *	Note: we don't ExecFreeResultType(scanstate)	 *		  because the rule manager depends on the tupType	 *		  returned by ExecMain().  So for now, this	 *		  is freed at end-transaction time.  -cim 6/2/91	 * ----------------	 */	ExecFreeProjectionInfo(&scanstate->cstate);	/* ----------------	 *	close the heap and index relations	 * ----------------	 */	ExecCloseR((Plan *) node);	/* ----------------	 *	free the scan keys used in scanning the indices	 * ----------------	 */	for (i = 0; i < numIndices; i++)	{		if (scanKeys[i] != NULL)			pfree(scanKeys[i]);	}	pfree(scanKeys);	pfree(numScanKeys);	if (runtimeKeyInfo)	{		for (i = 0; i < numIndices; i++)		{			List	   *qual;			int			n_keys;			qual = nth(i, indxqual);			n_keys = length(qual);			if (n_keys > 0)				pfree(runtimeKeyInfo[i]);		}		pfree(runtimeKeyInfo);	}	/* ----------------	 *	clear out tuple table slots	 * ----------------	 */	ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);	ExecClearTuple(scanstate->css_ScanTupleSlot);/*	  ExecClearTuple(scanstate->css_RawTupleSlot); */}/* ---------------------------------------------------------------- *		ExecIndexMarkPos * * old comments *		Marks scan position by marking the current index. *		Returns nothing. * ---------------------------------------------------------------- */voidExecIndexMarkPos(IndexScan *node){	IndexScanState *indexstate;	IndexScanDescPtr indexScanDescs;	IndexScanDesc scanDesc;	int			indexPtr;	indexstate = node->indxstate;	indexPtr = indexstate->iss_MarkIndexPtr = indexstate->iss_IndexPtr;	indexScanDescs = indexstate->iss_ScanDescs;	scanDesc = indexScanDescs[indexPtr];#ifdef NOT_USED	IndexScanMarkPosition(scanDesc);#endif	index_markpos(scanDesc);}/* ---------------------------------------------------------------- *		ExecIndexRestrPos * * old comments *		Restores scan position by restoring the current index. *		Returns nothing. * *		XXX Assumes previously marked scan position belongs to current index * ---------------------------------------------------------------- */voidExecIndexRestrPos(IndexScan *node){	IndexScanState *indexstate;	IndexScanDescPtr indexScanDescs;	IndexScanDesc scanDesc;	int			indexPtr;	indexstate = node->indxstate;	indexPtr = indexstate->iss_IndexPtr = indexstate->iss_MarkIndexPtr;	indexScanDescs = indexstate->iss_ScanDescs;	scanDesc = indexScanDescs[indexPtr];#ifdef NOT_USED	IndexScanRestorePosition(scanDesc);#endif	index_restrpos(scanDesc);}/* ---------------------------------------------------------------- *		ExecInitIndexScan  * *		Initializes the index scan's state information, creates *		scan keys, and opens the base and index relations. * *		Note: index scans have 2 sets of state information because *			  we have to keep track of the base relation and the *			  index relations. *

⌨️ 快捷键说明

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