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

📄 nbtutils.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * nbtutils.c *	  Utility code for Postgres btree implementation. * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.88.2.1 2008/04/16 23:59:51 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <time.h>#include "access/genam.h"#include "access/nbtree.h"#include "access/reloptions.h"#include "executor/execdebug.h"#include "miscadmin.h"#include "storage/lwlock.h"#include "storage/shmem.h"#include "utils/lsyscache.h"static bool _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,						 ScanKey leftarg, ScanKey rightarg,						 bool *result);static void _bt_mark_scankey_with_indoption(ScanKey skey, int16 *indoption);static void _bt_mark_scankey_required(ScanKey skey);static bool _bt_check_rowcompare(ScanKey skey,					 IndexTuple tuple, TupleDesc tupdesc,					 ScanDirection dir, bool *continuescan);/* * _bt_mkscankey *		Build an insertion scan key that contains comparison data from itup *		as well as comparator routines appropriate to the key datatypes. * *		The result is intended for use with _bt_compare(). */ScanKey_bt_mkscankey(Relation rel, IndexTuple itup){	ScanKey		skey;	TupleDesc	itupdesc;	int			natts;	int16	   *indoption;	int			i;	itupdesc = RelationGetDescr(rel);	natts = RelationGetNumberOfAttributes(rel);	indoption = rel->rd_indoption;	skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));	for (i = 0; i < natts; i++)	{		FmgrInfo   *procinfo;		Datum		arg;		bool		null;		int			flags;		/*		 * We can use the cached (default) support procs since no cross-type		 * comparison can be needed.		 */		procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);		arg = index_getattr(itup, i + 1, itupdesc, &null);		flags = (null ? SK_ISNULL : 0) | (indoption[i] << SK_BT_INDOPTION_SHIFT);		ScanKeyEntryInitializeWithInfo(&skey[i],									   flags,									   (AttrNumber) (i + 1),									   InvalidStrategy,									   InvalidOid,									   procinfo,									   arg);	}	return skey;}/* * _bt_mkscankey_nodata *		Build an insertion scan key that contains 3-way comparator routines *		appropriate to the key datatypes, but no comparison data.  The *		comparison data ultimately used must match the key datatypes. * *		The result cannot be used with _bt_compare(), unless comparison *		data is first stored into the key entries.	Currently this *		routine is only called by nbtsort.c and tuplesort.c, which have *		their own comparison routines. */ScanKey_bt_mkscankey_nodata(Relation rel){	ScanKey		skey;	int			natts;	int16	   *indoption;	int			i;	natts = RelationGetNumberOfAttributes(rel);	indoption = rel->rd_indoption;	skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));	for (i = 0; i < natts; i++)	{		FmgrInfo   *procinfo;		int			flags;		/*		 * We can use the cached (default) support procs since no cross-type		 * comparison can be needed.		 */		procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);		flags = SK_ISNULL | (indoption[i] << SK_BT_INDOPTION_SHIFT);		ScanKeyEntryInitializeWithInfo(&skey[i],									   flags,									   (AttrNumber) (i + 1),									   InvalidStrategy,									   InvalidOid,									   procinfo,									   (Datum) 0);	}	return skey;}/* * free a scan key made by either _bt_mkscankey or _bt_mkscankey_nodata. */void_bt_freeskey(ScanKey skey){	pfree(skey);}/* * free a retracement stack made by _bt_search. */void_bt_freestack(BTStack stack){	BTStack		ostack;	while (stack != NULL)	{		ostack = stack;		stack = stack->bts_parent;		pfree(ostack);	}}/* *	_bt_preprocess_keys() -- Preprocess scan keys * * The caller-supplied search-type keys (in scan->keyData[]) are copied to * so->keyData[] with possible transformation.	scan->numberOfKeys is * the number of input keys, so->numberOfKeys gets the number of output * keys (possibly less, never greater). * * The output keys are marked with additional sk_flag bits beyond the * system-standard bits supplied by the caller.  The DESC and NULLS_FIRST * indoption bits for the relevant index attribute are copied into the flags. * Also, for a DESC column, we commute (flip) all the sk_strategy numbers * so that the index sorts in the desired direction. * * One key purpose of this routine is to discover how many scan keys * must be satisfied to continue the scan.	It also attempts to eliminate * redundant keys and detect contradictory keys.  (If the index opfamily * provides incomplete sets of cross-type operators, we may fail to detect * redundant or contradictory keys, but we can survive that.) * * The output keys must be sorted by index attribute.  Presently we expect * (but verify) that the input keys are already so sorted --- this is done * by group_clauses_by_indexkey() in indxpath.c.  Some reordering of the keys * within each attribute may be done as a byproduct of the processing here, * but no other code depends on that. * * The output keys are marked with flags SK_BT_REQFWD and/or SK_BT_REQBKWD * if they must be satisfied in order to continue the scan forward or backward * respectively.  _bt_checkkeys uses these flags.  For example, if the quals * are "x = 1 AND y < 4 AND z < 5", then _bt_checkkeys will reject a tuple * (1,2,7), but we must continue the scan in case there are tuples (1,3,z). * But once we reach tuples like (1,4,z) we can stop scanning because no * later tuples could match.  This is reflected by marking the x and y keys, * but not the z key, with SK_BT_REQFWD.  In general, the keys for leading * attributes with "=" keys are marked both SK_BT_REQFWD and SK_BT_REQBKWD. * For the first attribute without an "=" key, any "<" and "<=" keys are * marked SK_BT_REQFWD while any ">" and ">=" keys are marked SK_BT_REQBKWD. * This can be seen to be correct by considering the above example.  Note * in particular that if there are no keys for a given attribute, the keys for * subsequent attributes can never be required; for instance "WHERE y = 4" * requires a full-index scan. * * If possible, redundant keys are eliminated: we keep only the tightest * >/>= bound and the tightest </<= bound, and if there's an = key then * that's the only one returned.  (So, we return either a single = key, * or one or two boundary-condition keys for each attr.)  However, if we * cannot compare two keys for lack of a suitable cross-type operator, * we cannot eliminate either.	If there are two such keys of the same * operator strategy, the second one is just pushed into the output array * without further processing here.  We may also emit both >/>= or both * </<= keys if we can't compare them.  The logic about required keys still * works if we don't eliminate redundant keys. * * As a byproduct of this work, we can detect contradictory quals such * as "x = 1 AND x > 2".  If we see that, we return so->qual_ok = FALSE, * indicating the scan need not be run at all since no tuples can match. * (In this case we do not bother completing the output key array!) * Again, missing cross-type operators might cause us to fail to prove the * quals contradictory when they really are, but the scan will work correctly. * * Row comparison keys are currently also treated without any smarts: * we just transfer them into the preprocessed array without any * editorialization.  We can treat them the same as an ordinary inequality * comparison on the row's first index column, for the purposes of the logic * about required keys. * * Note: the reason we have to copy the preprocessed scan keys into private * storage is that we are modifying the array based on comparisons of the * key argument values, which could change on a rescan.  Therefore we can't * overwrite the caller's data structure. */void_bt_preprocess_keys(IndexScanDesc scan){	BTScanOpaque so = (BTScanOpaque) scan->opaque;	int			numberOfKeys = scan->numberOfKeys;	int16	   *indoption = scan->indexRelation->rd_indoption;	int			new_numberOfKeys;	int			numberOfEqualCols;	ScanKey		inkeys;	ScanKey		outkeys;	ScanKey		cur;	ScanKey		xform[BTMaxStrategyNumber];	bool		test_result;	int			i,				j;	AttrNumber	attno;	/* initialize result variables */	so->qual_ok = true;	so->numberOfKeys = 0;	if (numberOfKeys < 1)		return;					/* done if qual-less scan */	inkeys = scan->keyData;	outkeys = so->keyData;	cur = &inkeys[0];	/* we check that input keys are correctly ordered */	if (cur->sk_attno < 1)		elog(ERROR, "btree index keys must be ordered by attribute");	/* We can short-circuit most of the work if there's just one key */	if (numberOfKeys == 1)	{		/*		 * We treat all btree operators as strict (even if they're not so		 * marked in pg_proc).	This means that it is impossible for an		 * operator condition with a NULL comparison constant to succeed, and		 * we can reject it right away.		 *		 * However, we now also support "x IS NULL" clauses as search		 * conditions, so in that case keep going.	The planner has not filled		 * in any particular strategy in this case, so set it to		 * BTEqualStrategyNumber --- we can treat IS NULL as an equality		 * operator for purposes of search strategy.		 */		if (cur->sk_flags & SK_ISNULL)		{			if (cur->sk_flags & SK_SEARCHNULL)			{				cur->sk_strategy = BTEqualStrategyNumber;				cur->sk_subtype = InvalidOid;			}			else				so->qual_ok = false;		}		_bt_mark_scankey_with_indoption(cur, indoption);		memcpy(outkeys, cur, sizeof(ScanKeyData));		so->numberOfKeys = 1;		/* We can mark the qual as required if it's for first index col */		if (cur->sk_attno == 1)			_bt_mark_scankey_required(outkeys);		return;	}	/*	 * Otherwise, do the full set of pushups.	 */	new_numberOfKeys = 0;	numberOfEqualCols = 0;	/*	 * Initialize for processing of keys for attr 1.	 *	 * xform[i] points to the currently best scan key of strategy type i+1; it	 * is NULL if we haven't yet found such a key for this attr.	 */	attno = 1;	memset(xform, 0, sizeof(xform));	/*	 * Loop iterates from 0 to numberOfKeys inclusive; we use the last pass to	 * handle after-last-key processing.  Actual exit from the loop is at the	 * "break" statement below.	 */	for (i = 0;; cur++, i++)	{		if (i < numberOfKeys)		{			/* See comments above about NULLs and IS NULL handling. */			/* Note: we assume SK_ISNULL is never set in a row header key */			if (cur->sk_flags & SK_ISNULL)			{				if (cur->sk_flags & SK_SEARCHNULL)				{					cur->sk_strategy = BTEqualStrategyNumber;					cur->sk_subtype = InvalidOid;				}				else				{					so->qual_ok = false;					return;				}			}		}		/*		 * If we are at the end of the keys for a particular attr, finish up		 * processing and emit the cleaned-up keys.		 */		if (i == numberOfKeys || cur->sk_attno != attno)		{			int			priorNumberOfEqualCols = numberOfEqualCols;			/* check input keys are correctly ordered */			if (i < numberOfKeys && cur->sk_attno < attno)				elog(ERROR, "btree index keys must be ordered by attribute");			/*			 * If = has been specified, all other keys can be eliminated as			 * redundant.  In case of key > 2 && key == 1 we can set qual_ok			 * to false and abandon further processing.			 */			if (xform[BTEqualStrategyNumber - 1])			{				ScanKey		eq = xform[BTEqualStrategyNumber - 1];				for (j = BTMaxStrategyNumber; --j >= 0;)				{					ScanKey		chk = xform[j];					if (!chk || j == (BTEqualStrategyNumber - 1))						continue;					/* IS NULL together with any other predicate must fail */					if (eq->sk_flags & SK_SEARCHNULL)					{						so->qual_ok = false;						return;					}					if (_bt_compare_scankey_args(scan, chk, eq, chk,												 &test_result))					{						if (!test_result)						{							/* keys proven mutually contradictory */							so->qual_ok = false;							return;						}						/* else discard the redundant non-equality key */						xform[j] = NULL;					}					/* else, cannot determine redundancy, keep both keys */				}				/* track number of attrs for which we have "=" keys */				numberOfEqualCols++;			}			/* try to keep only one of <, <= */			if (xform[BTLessStrategyNumber - 1]				&& xform[BTLessEqualStrategyNumber - 1])			{				ScanKey		lt = xform[BTLessStrategyNumber - 1];				ScanKey		le = xform[BTLessEqualStrategyNumber - 1];				if (_bt_compare_scankey_args(scan, le, lt, le,											 &test_result))				{					if (test_result)						xform[BTLessEqualStrategyNumber - 1] = NULL;					else						xform[BTLessStrategyNumber - 1] = NULL;				}			}			/* try to keep only one of >, >= */			if (xform[BTGreaterStrategyNumber - 1]				&& xform[BTGreaterEqualStrategyNumber - 1])			{				ScanKey		gt = xform[BTGreaterStrategyNumber - 1];				ScanKey		ge = xform[BTGreaterEqualStrategyNumber - 1];				if (_bt_compare_scankey_args(scan, ge, gt, ge,											 &test_result))				{					if (test_result)						xform[BTGreaterEqualStrategyNumber - 1] = NULL;					else						xform[BTGreaterStrategyNumber - 1] = NULL;				}			}			/*			 * Emit the cleaned-up keys into the outkeys[] array, and then			 * mark them if they are required.	They are required (possibly			 * only in one direction) if all attrs before this one had "=".			 */			for (j = BTMaxStrategyNumber; --j >= 0;)			{				if (xform[j])				{					ScanKey		outkey = &outkeys[new_numberOfKeys++];					memcpy(outkey, xform[j], sizeof(ScanKeyData));					if (priorNumberOfEqualCols == attno - 1)						_bt_mark_scankey_required(outkey);				}			}			/*			 * Exit loop here if done.			 */			if (i == numberOfKeys)				break;			/* Re-initialize for new attno */			attno = cur->sk_attno;			memset(xform, 0, sizeof(xform));		}		/* apply indoption to scankey (might change sk_strategy!) */		_bt_mark_scankey_with_indoption(cur, indoption);		/* check strategy this key's operator corresponds to */		j = cur->sk_strategy - 1;		/* if row comparison, push it directly to the output array */		if (cur->sk_flags & SK_ROW_HEADER)		{			ScanKey		outkey = &outkeys[new_numberOfKeys++];			memcpy(outkey, cur, sizeof(ScanKeyData));			if (numberOfEqualCols == attno - 1)				_bt_mark_scankey_required(outkey);			/*			 * We don't support RowCompare using equality; such a qual would			 * mess up the numberOfEqualCols tracking.

⌨️ 快捷键说明

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