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

📄 nodeindexscan.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 2 页
字号:
	{		if (indexScanDescs[i] != NULL)			index_endscan(indexScanDescs[i]);		if (indexRelationDescs[i] != NULL)			index_close(indexRelationDescs[i]);	}	/*	 * close the heap relation.	 *	 * Currently, we do not release the AccessShareLock acquired by	 * ExecInitIndexScan.  This lock should be held till end of	 * transaction. (There is a faction that considers this too much	 * locking, however.)	 */	heap_close(relation, NoLock);}/* ---------------------------------------------------------------- *		ExecIndexMarkPos * * old comments *		Marks scan position by marking the current index. *		Returns nothing. * ---------------------------------------------------------------- */voidExecIndexMarkPos(IndexScanState *node){	IndexScanDescPtr indexScanDescs;	IndexScanDesc scanDesc;	int			indexPtr;	indexPtr = node->iss_MarkIndexPtr = node->iss_IndexPtr;	if (indexPtr >= 0 && indexPtr < node->iss_NumIndices)	{		indexScanDescs = node->iss_ScanDescs;		scanDesc = indexScanDescs[indexPtr];		index_markpos(scanDesc);	}}/* ---------------------------------------------------------------- *		ExecIndexRestrPos * * old comments *		Restores scan position by restoring the current index. *		Returns nothing. * ---------------------------------------------------------------- */voidExecIndexRestrPos(IndexScanState *node){	IndexScanDescPtr indexScanDescs;	IndexScanDesc scanDesc;	int			indexPtr;	indexPtr = node->iss_IndexPtr = node->iss_MarkIndexPtr;	if (indexPtr >= 0 && indexPtr < node->iss_NumIndices)	{		indexScanDescs = node->iss_ScanDescs;		scanDesc = indexScanDescs[indexPtr];		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. * * old comments *		Creates the run-time state information for the node and *		sets the relation id to contain relevant descriptors. * *		Parameters: *		  node: IndexNode node produced by the planner. *		  estate: the execution state initialized in InitPlan. * ---------------------------------------------------------------- */IndexScanState *ExecInitIndexScan(IndexScan *node, EState *estate){	IndexScanState *indexstate;	List	   *indxqual;	List	   *indxid;	List	   *listscan;	int			i;	int			numIndices;	int			indexPtr;	ScanKey    *scanKeys;	int		   *numScanKeys;	RelationPtr indexDescs;	IndexScanDescPtr scanDescs;	ExprState ***runtimeKeyInfo;	bool		have_runtime_keys;	RangeTblEntry *rtentry;	Index		relid;	Oid			reloid;	Relation	currentRelation;	/*	 * create state structure	 */	indexstate = makeNode(IndexScanState);	indexstate->ss.ps.plan = (Plan *) node;	indexstate->ss.ps.state = estate;	/*	 * Miscellaneous initialization	 *	 * create expression context for node	 */	ExecAssignExprContext(estate, &indexstate->ss.ps);	/*	 * initialize child expressions	 */	indexstate->ss.ps.targetlist = (List *)		ExecInitExpr((Expr *) node->scan.plan.targetlist,					 (PlanState *) indexstate);	indexstate->ss.ps.qual = (List *)		ExecInitExpr((Expr *) node->scan.plan.qual,					 (PlanState *) indexstate);	indexstate->indxqual = (List *)		ExecInitExpr((Expr *) node->indxqual,					 (PlanState *) indexstate);	indexstate->indxqualorig = (List *)		ExecInitExpr((Expr *) node->indxqualorig,					 (PlanState *) indexstate);#define INDEXSCAN_NSLOTS 2	/*	 * tuple table initialization	 */	ExecInitResultTupleSlot(estate, &indexstate->ss.ps);	ExecInitScanTupleSlot(estate, &indexstate->ss);	/*	 * Initialize index-specific scan state	 */	indexstate->iss_NumIndices = 0;	indexstate->iss_IndexPtr = -1;	indexstate->iss_ScanKeys = NULL;	indexstate->iss_NumScanKeys = NULL;	indexstate->iss_RuntimeKeyInfo = NULL;	indexstate->iss_RuntimeContext = NULL;	indexstate->iss_RuntimeKeysReady = false;	indexstate->iss_RelationDescs = NULL;	indexstate->iss_ScanDescs = NULL;	/*	 * get the index node information	 */	indxid = node->indxid;	numIndices = length(indxid);	indexPtr = -1;	CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);	/*	 * scanKeys is used to keep track of the ScanKey's. This is needed	 * because a single scan may use several indices and each index has	 * its own ScanKey.	 */	numScanKeys = (int *) palloc(numIndices * sizeof(int));	scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));	indexDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));	scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));	/*	 * initialize space for runtime key info (may not be needed)	 */	have_runtime_keys = false;	runtimeKeyInfo = (ExprState ***) palloc0(numIndices * sizeof(ExprState **));	/*	 * build the index scan keys from the index qualification	 */	indxqual = node->indxqual;	for (i = 0; i < numIndices; i++)	{		int			j;		List	   *qual;		int			n_keys;		ScanKey		scan_keys;		ExprState **run_keys;		qual = lfirst(indxqual);		indxqual = lnext(indxqual);		n_keys = length(qual);		scan_keys = (n_keys <= 0) ? (ScanKey) NULL :			(ScanKey) palloc(n_keys * sizeof(ScanKeyData));		run_keys = (n_keys <= 0) ? (ExprState **) NULL :			(ExprState **) palloc(n_keys * sizeof(ExprState *));		CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);		/*		 * for each opclause in the given qual, convert each qual's		 * opclause into a single scan key		 */		listscan = qual;		for (j = 0; j < n_keys; j++)		{			OpExpr	   *clause; /* one clause of index qual */			Expr	   *leftop; /* expr on lhs of operator */			Expr	   *rightop;	/* expr on rhs ... */			bits16		flags = 0;			int			scanvar;	/* which var identifies varattno */			AttrNumber	varattno = 0;	/* att number used in scan */			Oid			opfuncid;		/* operator id used in scan */			Datum		scanvalue = 0;	/* value used in scan (if const) */			/*			 * extract clause information from the qualification			 */			clause = (OpExpr *) lfirst(listscan);			listscan = lnext(listscan);			if (!IsA(clause, OpExpr))				elog(ERROR, "indxqual is not an OpExpr");			opfuncid = clause->opfuncid;			/*			 * Here we figure out the contents of the index qual. The			 * usual case is (var op const) or (const op var) which means			 * we form a scan key for the attribute listed in the var node			 * and use the value of the const.			 *			 * If we don't have a const node, then it means that one of the			 * var nodes refers to the "scan" tuple and is used to			 * determine which attribute to scan, and the other expression			 * is used to calculate the value used in scanning the index.			 *			 * This means our index scan's scan key is a function of			 * information obtained during the execution of the plan in			 * which case we need to recalculate the index scan key at run			 * time.			 *			 * Hence, we set have_runtime_keys to true and place the			 * appropriate subexpression in run_keys. The corresponding			 * scan key values are recomputed at run time.			 *			 * XXX Although this code *thinks* it can handle an indexqual			 * with the indexkey on either side, in fact it cannot.			 * Indexscans only work with quals that have the indexkey on			 * the left (the planner/optimizer makes sure it never passes			 * anything else).	The reason: the scankey machinery has no			 * provision for distinguishing which side of the operator is			 * the indexed attribute and which is the compared-to			 * constant. It just assumes that the attribute is on the left			 * :-(			 *			 * I am leaving this code able to support both ways, even though			 * half of it is dead code, on the off chance that someone			 * will fix the scankey machinery someday --- tgl 8/11/99.			 */			scanvar = NO_OP;			run_keys[j] = NULL;			/*			 * determine information in leftop			 */			leftop = (Expr *) get_leftop((Expr *) clause);			if (leftop && IsA(leftop, RelabelType))				leftop = ((RelabelType *) leftop)->arg;			Assert(leftop != NULL);			if (IsA(leftop, Var) &&				var_is_rel((Var *) leftop))			{				/*				 * if the leftop is a "rel-var", then it means that it is				 * a var node which tells us which attribute to use for				 * our scan key.				 */				varattno = ((Var *) leftop)->varattno;				scanvar = LEFT_OP;			}			else if (IsA(leftop, Const))			{				/*				 * if the leftop is a const node then it means it				 * identifies the value to place in our scan key.				 */				scanvalue = ((Const *) leftop)->constvalue;				if (((Const *) leftop)->constisnull)					flags |= SK_ISNULL;			}			else			{				/*				 * otherwise, the leftop contains an expression evaluable				 * at runtime to figure out the value to place in our scan				 * key.				 */				have_runtime_keys = true;				run_keys[j] = ExecInitExpr(leftop, (PlanState *) indexstate);			}			/*			 * now determine information in rightop			 */			rightop = (Expr *) get_rightop((Expr *) clause);			if (rightop && IsA(rightop, RelabelType))				rightop = ((RelabelType *) rightop)->arg;			Assert(rightop != NULL);			if (IsA(rightop, Var) &&				var_is_rel((Var *) rightop))			{				/*				 * here we make sure only one op identifies the				 * scan-attribute...				 */				if (scanvar == LEFT_OP)					elog(ERROR, "both left and right operands are rel-vars");				/*				 * if the rightop is a "rel-var", then it means that it is				 * a var node which tells us which attribute to use for				 * our scan key.				 */				varattno = ((Var *) rightop)->varattno;				scanvar = RIGHT_OP;			}			else if (IsA(rightop, Const))			{				/*				 * if the rightop is a const node then it means it				 * identifies the value to place in our scan key.				 */				scanvalue = ((Const *) rightop)->constvalue;				if (((Const *) rightop)->constisnull)					flags |= SK_ISNULL;			}			else			{				/*				 * otherwise, the rightop contains an expression evaluable				 * at runtime to figure out the value to place in our scan				 * key.				 */				have_runtime_keys = true;				run_keys[j] = ExecInitExpr(rightop, (PlanState *) indexstate);			}			/*			 * now check that at least one op tells us the scan			 * attribute...			 */			if (scanvar == NO_OP)				elog(ERROR, "neither left nor right operand refer to scan relation");			/*			 * initialize the scan key's fields appropriately			 */			ScanKeyEntryInitialize(&scan_keys[j],								   flags,								   varattno,	/* attribute number to												 * scan */								   opfuncid,	/* reg proc to use */								   scanvalue);	/* constant */		}		/*		 * store the key information into our arrays.		 */		numScanKeys[i] = n_keys;		scanKeys[i] = scan_keys;		runtimeKeyInfo[i] = run_keys;	}	indexstate->iss_NumIndices = numIndices;	if (ScanDirectionIsBackward(node->indxorderdir))		indexPtr = numIndices;	indexstate->iss_IndexPtr = indexPtr;	indexstate->iss_ScanKeys = scanKeys;	indexstate->iss_NumScanKeys = numScanKeys;	/*	 * If all of our keys have the form (op var const) , then we have no	 * runtime keys so we store NULL in the runtime key info. Otherwise	 * runtime key info contains an array of pointers (one for each index)	 * to arrays of flags (one for each key) which indicate that the qual	 * needs to be evaluated at runtime. -cim 10/24/89	 *	 * If we do have runtime keys, we need an ExprContext to evaluate them;	 * the node's standard context won't do because we want to reset that	 * context for every tuple.  So, build another context just like the	 * other one... -tgl 7/11/00	 */	if (have_runtime_keys)	{		ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;		ExecAssignExprContext(estate, &indexstate->ss.ps);		indexstate->iss_RuntimeKeyInfo = runtimeKeyInfo;		indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;		indexstate->ss.ps.ps_ExprContext = stdecontext;	}	else	{		indexstate->iss_RuntimeKeyInfo = NULL;		indexstate->iss_RuntimeContext = NULL;		/* Get rid of the speculatively-allocated flag arrays, too */		for (i = 0; i < numIndices; i++)		{			if (runtimeKeyInfo[i] != NULL)				pfree(runtimeKeyInfo[i]);		}		pfree(runtimeKeyInfo);	}	/*	 * open the base relation and acquire AccessShareLock on it.	 */	relid = node->scan.scanrelid;	rtentry = rt_fetch(relid, estate->es_range_table);	reloid = rtentry->relid;	currentRelation = heap_open(reloid, AccessShareLock);	indexstate->ss.ss_currentRelation = currentRelation;	indexstate->ss.ss_currentScanDesc = NULL;	/* no heap scan here */	/*	 * get the scan type from the relation descriptor.	 */	ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation), false);	/*	 * open the index relations and initialize relation and scan	 * descriptors.  Note we acquire no locks here; the index machinery	 * does its own locks and unlocks.	(We rely on having AccessShareLock	 * on the parent table to ensure the index won't go away!)	 */	listscan = indxid;	for (i = 0; i < numIndices; i++)	{		Oid			indexOid = lfirsto(listscan);		indexDescs[i] = index_open(indexOid);		scanDescs[i] = index_beginscan(currentRelation,									   indexDescs[i],									   estate->es_snapshot,									   numScanKeys[i],									   scanKeys[i]);		listscan = lnext(listscan);	}	indexstate->iss_RelationDescs = indexDescs;	indexstate->iss_ScanDescs = scanDescs;	/*	 * Initialize result tuple type and projection info.	 */	ExecAssignResultTypeFromTL(&indexstate->ss.ps);	ExecAssignScanProjectionInfo(&indexstate->ss);	/*	 * Initialize hash table if needed.	 */	if (numIndices > 1)		create_duphash(indexstate);	else		indexstate->iss_DupHash = NULL;	/*	 * all done.	 */	return indexstate;}static voidcreate_duphash(IndexScanState *node){	HASHCTL		hash_ctl;	long		nbuckets;	node->iss_MaxHash = (SortMem * 1024L) /		(MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(DupHashTabEntry)));	MemSet(&hash_ctl, 0, sizeof(hash_ctl));	hash_ctl.keysize = SizeOfIptrData;	hash_ctl.entrysize = sizeof(DupHashTabEntry);	hash_ctl.hash = tag_hash;	hash_ctl.hcxt = CurrentMemoryContext;	nbuckets = (long) ceil(node->ss.ps.plan->plan_rows);	if (nbuckets < 1)		nbuckets = 1;	if (nbuckets > node->iss_MaxHash)		nbuckets = node->iss_MaxHash;	node->iss_DupHash = hash_create("DupHashTable",									nbuckets,									&hash_ctl,									HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);	if (node->iss_DupHash == NULL)		ereport(ERROR,				(errcode(ERRCODE_OUT_OF_MEMORY),				 errmsg("out of memory")));}intExecCountSlotsIndexScan(IndexScan *node){	return ExecCountSlotsNode(outerPlan((Plan *) node)) +		ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;}

⌨️ 快捷键说明

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