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

📄 nbtutils.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
			 */			Assert(j != (BTEqualStrategyNumber - 1));			continue;		}		/* have we seen one of these before? */		if (xform[j] == NULL)		{			/* nope, so remember this scankey */			xform[j] = cur;		}		else		{			/* yup, keep only the more restrictive key */			/* if either arg is NULL, don't try to compare */			if ((cur->sk_flags | xform[j]->sk_flags) & SK_ISNULL)			{				/* at least one of them must be an IS NULL clause */				Assert(j == (BTEqualStrategyNumber - 1));				Assert((cur->sk_flags | xform[j]->sk_flags) & SK_SEARCHNULL);				/* if one is and one isn't, the search must fail */				if ((cur->sk_flags ^ xform[j]->sk_flags) & SK_SEARCHNULL)				{					so->qual_ok = false;					return;				}				/* we have duplicate IS NULL clauses, ignore the newer one */				continue;			}			if (_bt_compare_scankey_args(scan, cur, cur, xform[j],										 &test_result))			{				if (test_result)					xform[j] = cur;				else if (j == (BTEqualStrategyNumber - 1))				{					/* key == a && key == b, but a != b */					so->qual_ok = false;					return;				}				/* else old key is more restrictive, keep it */			}			else			{				/*				 * We can't determine which key is more restrictive.  Keep the				 * previous one in xform[j] and push this one directly to the				 * output array.				 */				ScanKey		outkey = &outkeys[new_numberOfKeys++];				memcpy(outkey, cur, sizeof(ScanKeyData));				if (numberOfEqualCols == attno - 1)					_bt_mark_scankey_required(outkey);			}		}	}	so->numberOfKeys = new_numberOfKeys;}/* * Compare two scankey values using a specified operator.  Both values * must be already known non-NULL. * * The test we want to perform is logically "leftarg op rightarg", where * leftarg and rightarg are the sk_argument values in those ScanKeys, and * the comparison operator is the one in the op ScanKey.  However, in * cross-data-type situations we may need to look up the correct operator in * the index's opfamily: it is the one having amopstrategy = op->sk_strategy * and amoplefttype/amoprighttype equal to the two argument datatypes. * * If the opfamily doesn't supply a complete set of cross-type operators we * may not be able to make the comparison.	If we can make the comparison * we store the operator result in *result and return TRUE.  We return FALSE * if the comparison could not be made. * * Note: op always points at the same ScanKey as either leftarg or rightarg. * Since we don't scribble on the scankeys, this aliasing should cause no * trouble. * * Note: this routine needs to be insensitive to any DESC option applied * to the index column.  For example, "x < 4" is a tighter constraint than * "x < 5" regardless of which way the index is sorted.  We don't worry about * NULLS FIRST/LAST either, since the given values are never nulls. */static bool_bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,						 ScanKey leftarg, ScanKey rightarg,						 bool *result){	Relation	rel = scan->indexRelation;	Oid			lefttype,				righttype,				optype,				opcintype,				cmp_op;	StrategyNumber strat;	/*	 * The opfamily we need to worry about is identified by the index column.	 */	Assert(leftarg->sk_attno == rightarg->sk_attno);	opcintype = rel->rd_opcintype[leftarg->sk_attno - 1];	/*	 * Determine the actual datatypes of the ScanKey arguments.  We have to	 * support the convention that sk_subtype == InvalidOid means the opclass	 * input type; this is a hack to simplify life for ScanKeyInit().	 */	lefttype = leftarg->sk_subtype;	if (lefttype == InvalidOid)		lefttype = opcintype;	righttype = rightarg->sk_subtype;	if (righttype == InvalidOid)		righttype = opcintype;	optype = op->sk_subtype;	if (optype == InvalidOid)		optype = opcintype;	/*	 * If leftarg and rightarg match the types expected for the "op" scankey,	 * we can use its already-looked-up comparison function.	 */	if (lefttype == opcintype && righttype == optype)	{		*result = DatumGetBool(FunctionCall2(&op->sk_func,											 leftarg->sk_argument,											 rightarg->sk_argument));		return true;	}	/*	 * Otherwise, we need to go to the syscache to find the appropriate	 * operator.  (This cannot result in infinite recursion, since no	 * indexscan initiated by syscache lookup will use cross-data-type	 * operators.)	 *	 * If the sk_strategy was flipped by _bt_mark_scankey_with_indoption, we	 * have to un-flip it to get the correct opfamily member.	 */	strat = op->sk_strategy;	if (op->sk_flags & SK_BT_DESC)		strat = BTCommuteStrategyNumber(strat);	cmp_op = get_opfamily_member(rel->rd_opfamily[leftarg->sk_attno - 1],								 lefttype,								 righttype,								 strat);	if (OidIsValid(cmp_op))	{		RegProcedure cmp_proc = get_opcode(cmp_op);		if (RegProcedureIsValid(cmp_proc))		{			*result = DatumGetBool(OidFunctionCall2(cmp_proc,													leftarg->sk_argument,													rightarg->sk_argument));			return true;		}	}	/* Can't make the comparison */	*result = false;			/* suppress compiler warnings */	return false;}/* * Mark a scankey with info from the index's indoption array. * * We copy the appropriate indoption value into the scankey sk_flags * (shifting to avoid clobbering system-defined flag bits).  Also, if * the DESC option is set, commute (flip) the operator strategy number. * * This function is applied to the *input* scankey structure; therefore * on a rescan we will be looking at already-processed scankeys.  Hence * we have to be careful not to re-commute the strategy if we already did it. * It's a bit ugly to modify the caller's copy of the scankey but in practice * there shouldn't be any problem, since the index's indoptions are certainly * not going to change while the scankey survives. */static void_bt_mark_scankey_with_indoption(ScanKey skey, int16 *indoption){	int			addflags;	addflags = indoption[skey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;	if ((addflags & SK_BT_DESC) && !(skey->sk_flags & SK_BT_DESC))		skey->sk_strategy = BTCommuteStrategyNumber(skey->sk_strategy);	skey->sk_flags |= addflags;	if (skey->sk_flags & SK_ROW_HEADER)	{		ScanKey		subkey = (ScanKey) DatumGetPointer(skey->sk_argument);		for (;;)		{			Assert(subkey->sk_flags & SK_ROW_MEMBER);			addflags = indoption[subkey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;			if ((addflags & SK_BT_DESC) && !(subkey->sk_flags & SK_BT_DESC))				subkey->sk_strategy = BTCommuteStrategyNumber(subkey->sk_strategy);			subkey->sk_flags |= addflags;			if (subkey->sk_flags & SK_ROW_END)				break;			subkey++;		}	}}/* * Mark a scankey as "required to continue the scan". * * Depending on the operator type, the key may be required for both scan * directions or just one.	Also, if the key is a row comparison header, * we have to mark the appropriate subsidiary ScanKeys as required.  In * such cases, the first subsidiary key is required, but subsequent ones * are required only as long as they correspond to successive index columns * and match the leading column as to sort direction. * Otherwise the row comparison ordering is different from the index ordering * and so we can't stop the scan on the basis of those lower-order columns. * * Note: when we set required-key flag bits in a subsidiary scankey, we are * scribbling on a data structure belonging to the index AM's caller, not on * our private copy.  This should be OK because the marking will not change * from scan to scan within a query, and so we'd just re-mark the same way * anyway on a rescan.	Something to keep an eye on though. */static void_bt_mark_scankey_required(ScanKey skey){	int			addflags;	switch (skey->sk_strategy)	{		case BTLessStrategyNumber:		case BTLessEqualStrategyNumber:			addflags = SK_BT_REQFWD;			break;		case BTEqualStrategyNumber:			addflags = SK_BT_REQFWD | SK_BT_REQBKWD;			break;		case BTGreaterEqualStrategyNumber:		case BTGreaterStrategyNumber:			addflags = SK_BT_REQBKWD;			break;		default:			elog(ERROR, "unrecognized StrategyNumber: %d",				 (int) skey->sk_strategy);			addflags = 0;		/* keep compiler quiet */			break;	}	skey->sk_flags |= addflags;	if (skey->sk_flags & SK_ROW_HEADER)	{		ScanKey		subkey = (ScanKey) DatumGetPointer(skey->sk_argument);		AttrNumber	attno = skey->sk_attno;		/* First subkey should be same as the header says */		Assert(subkey->sk_attno == attno);		for (;;)		{			Assert(subkey->sk_flags & SK_ROW_MEMBER);			if (subkey->sk_attno != attno)				break;			/* non-adjacent key, so not required */			if (subkey->sk_strategy != skey->sk_strategy)				break;			/* wrong direction, so not required */			subkey->sk_flags |= addflags;			if (subkey->sk_flags & SK_ROW_END)				break;			subkey++;			attno++;		}	}}/* * Test whether an indextuple satisfies all the scankey conditions. * * If so, copy its TID into scan->xs_ctup.t_self, and return TRUE. * If not, return FALSE (xs_ctup is not changed). * * If the tuple fails to pass the qual, we also determine whether there's * any need to continue the scan beyond this tuple, and set *continuescan * accordingly.  See comments for _bt_preprocess_keys(), above, about how * this is done. * * scan: index scan descriptor (containing a search-type scankey) * page: buffer page containing index tuple * offnum: offset number of index tuple (must be a valid item!) * dir: direction we are scanning in * continuescan: output parameter (will be set correctly in all cases) */bool_bt_checkkeys(IndexScanDesc scan,			  Page page, OffsetNumber offnum,			  ScanDirection dir, bool *continuescan){	ItemId		iid = PageGetItemId(page, offnum);	bool		tuple_valid;	IndexTuple	tuple;	TupleDesc	tupdesc;	BTScanOpaque so;	int			keysz;	int			ikey;	ScanKey		key;	*continuescan = true;		/* default assumption */	/*	 * If the scan specifies not to return killed tuples, then we treat a	 * killed tuple as not passing the qual.  Most of the time, it's a win to	 * not bother examining the tuple's index keys, but just return	 * immediately with continuescan = true to proceed to the next tuple.	 * However, if this is the last tuple on the page, we should check the	 * index keys to prevent uselessly advancing to the next page.	 */	if (scan->ignore_killed_tuples && ItemIdIsDead(iid))	{		/* return immediately if there are more tuples on the page */		if (ScanDirectionIsForward(dir))		{			if (offnum < PageGetMaxOffsetNumber(page))				return false;		}		else		{			BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);			if (offnum > P_FIRSTDATAKEY(opaque))				return false;		}		/*		 * OK, we want to check the keys, but we'll return FALSE even if the		 * tuple passes the key tests.		 */		tuple_valid = false;	}	else		tuple_valid = true;	tuple = (IndexTuple) PageGetItem(page, iid);	IncrIndexProcessed();	tupdesc = RelationGetDescr(scan->indexRelation);	so = (BTScanOpaque) scan->opaque;	keysz = so->numberOfKeys;	for (key = so->keyData, ikey = 0; ikey < keysz; key++, ikey++)	{		Datum		datum;		bool		isNull;		Datum		test;		/* row-comparison keys need special processing */		if (key->sk_flags & SK_ROW_HEADER)		{			if (_bt_check_rowcompare(key, tuple, tupdesc, dir, continuescan))				continue;			return false;		}		datum = index_getattr(tuple,							  key->sk_attno,							  tupdesc,							  &isNull);		if (key->sk_flags & SK_ISNULL)		{			/* Handle IS NULL tests */			Assert(key->sk_flags & SK_SEARCHNULL);			if (isNull)				continue;		/* tuple satisfies this qual */			/*			 * Tuple fails this qual.  If it's a required qual for the current			 * scan direction, then we can conclude no further tuples will			 * pass, either.			 */			if ((key->sk_flags & SK_BT_REQFWD) &&				ScanDirectionIsForward(dir))				*continuescan = false;			else if ((key->sk_flags & SK_BT_REQBKWD) &&					 ScanDirectionIsBackward(dir))				*continuescan = false;			/*			 * In any case, this indextuple doesn't match the qual.			 */			return false;		}		if (isNull)		{			if (key->sk_flags & SK_BT_NULLS_FIRST)			{				/*				 * Since NULLs are sorted before non-NULLs, we know we have				 * reached the lower limit of the range of values for this				 * index attr.	On a backward scan, we can stop if this qual				 * is one of the "must match" subset.  On a forward scan,				 * however, we should keep going.				 */				if ((key->sk_flags & SK_BT_REQBKWD) &&					ScanDirectionIsBackward(dir))					*continuescan = false;			}			else			{				/*				 * Since NULLs are sorted after non-NULLs, we know we have				 * reached the upper limit of the range of values for this				 * index attr.	On a forward scan, we can stop if this qual is				 * one of the "must match" subset.	On a backward scan,				 * however, we should keep going.				 */				if ((key->sk_flags & SK_BT_REQFWD) &&					ScanDirectionIsForward(dir))					*continuescan = false;			}			/*			 * In any case, this indextuple doesn't match the qual.			 */			return false;		}		test = FunctionCall2(&key->sk_func, datum, key->sk_argument);		if (!DatumGetBool(test))		{			/*			 * Tuple fails this qual.  If it's a required qual for the current			 * scan direction, then we can conclude no further tuples will			 * pass, either.			 *			 * Note: because we stop the scan as soon as any required equality			 * qual fails, it is critical that equality quals be used for the			 * initial positioning in _bt_first() when they are available. See			 * comments in _bt_first().			 */			if ((key->sk_flags & SK_BT_REQFWD) &&				ScanDirectionIsForward(dir))				*continuescan = false;			else if ((key->sk_flags & SK_BT_REQBKWD) &&					 ScanDirectionIsBackward(dir))				*continuescan = false;			/*			 * In any case, this indextuple doesn't match the qual.			 */			return false;		}	}	/* If we get here, the tuple passes all index quals. */	if (tuple_valid)		scan->xs_ctup.t_self = tuple->t_tid;	return tuple_valid;}

⌨️ 快捷键说明

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