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

📄 indxpath.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
	} while (!DoneMatchingIndexKeys(classes));	if (!*found_clause && !found_outer_clause)		return NIL;				/* no indexable clauses anywhere */	return clausegroup_list;}/* * match_clause_to_indexcol() *	  Determines whether a restriction clause matches a column of an index. * *	  To match a normal index, the clause: * *	  (1)  must be in the form (indexkey op const) or (const op indexkey); *		   and *	  (2)  must contain an operator which is in the same class as the index *		   operator for this column, or is a "special" operator as recognized *		   by match_special_index_operator(). * *	  Our definition of "const" is pretty liberal: we allow Vars belonging *	  to the caller-specified outer_relids relations (which had better not *	  include the relation whose index is being tested).  outer_relids should *	  be NULL when checking simple restriction clauses, and the outer side *	  of the join when building a join inner scan.	Other than that, the *	  only thing we don't like is volatile functions. * *	  Note: in most cases we already know that the clause as a whole uses *	  vars from the interesting set of relations.  The reason for the *	  outer_relids test is to reject clauses like (a.f1 OP (b.f2 OP a.f3)); *	  that's not processable by an indexscan nestloop join on A, whereas *	  (a.f1 OP (b.f2 OP c.f3)) is. * *	  Presently, the executor can only deal with indexquals that have the *	  indexkey on the left, so we can only use clauses that have the indexkey *	  on the right if we can commute the clause to put the key on the left. *	  We do not actually do the commuting here, but we check whether a *	  suitable commutator operator is available. * *	  For boolean indexes, it is also possible to match the clause directly *	  to the indexkey; or perhaps the clause is (NOT indexkey). * * 'index' is the index of interest. * 'indexcol' is a column number of 'index' (counting from 0). * 'opclass' is the corresponding operator class. * 'rinfo' is the clause to be tested (as a RestrictInfo node). * * Returns true if the clause can be used with this index key. * * NOTE:  returns false if clause is an OR or AND clause; it is the * responsibility of higher-level routines to cope with those. */static boolmatch_clause_to_indexcol(IndexOptInfo *index,						 int indexcol,						 Oid opclass,						 RestrictInfo *rinfo,						 Relids outer_relids){	Expr	   *clause = rinfo->clause;	Node	   *leftop,			   *rightop;	/* First check for boolean-index cases. */	if (IsBooleanOpclass(opclass))	{		if (match_boolean_index_clause((Node *) clause, indexcol, index))			return true;	}	/* Else clause must be a binary opclause. */	if (!is_opclause(clause))		return false;	leftop = get_leftop(clause);	rightop = get_rightop(clause);	if (!leftop || !rightop)		return false;	/*	 * Check for clauses of the form: (indexkey operator constant) or	 * (constant operator indexkey).  See above notes about const-ness.	 */	if (match_index_to_operand(leftop, indexcol, index) &&		bms_is_subset(rinfo->right_relids, outer_relids) &&		!contain_volatile_functions(rightop))	{		if (is_indexable_operator(clause, opclass, true))			return true;		/*		 * If we didn't find a member of the index's opclass, see whether it		 * is a "special" indexable operator.		 */		if (match_special_index_operator(clause, opclass, true))			return true;		return false;	}	if (match_index_to_operand(rightop, indexcol, index) &&		bms_is_subset(rinfo->left_relids, outer_relids) &&		!contain_volatile_functions(leftop))	{		if (is_indexable_operator(clause, opclass, false))			return true;		/*		 * If we didn't find a member of the index's opclass, see whether it		 * is a "special" indexable operator.		 */		if (match_special_index_operator(clause, opclass, false))			return true;		return false;	}	return false;}/* * indexable_operator *	  Does a binary opclause contain an operator matching the index opclass? * * If the indexkey is on the right, what we actually want to know * is whether the operator has a commutator operator that matches * the index's opclass. * * Returns the OID of the matching operator, or InvalidOid if no match. * (Formerly, this routine might return a binary-compatible operator * rather than the original one, but that kluge is history.) */static Oidindexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left){	Oid			expr_op = ((OpExpr *) clause)->opno;	Oid			commuted_op;	/* Get the commuted operator if necessary */	if (indexkey_on_left)		commuted_op = expr_op;	else		commuted_op = get_commutator(expr_op);	if (commuted_op == InvalidOid)		return InvalidOid;	/* OK if the (commuted) operator is a member of the index's opclass */	if (op_in_opclass(commuted_op, opclass))		return expr_op;	return InvalidOid;}/**************************************************************************** *				----  ROUTINES TO DO PARTIAL INDEX PREDICATE TESTS	---- ****************************************************************************//* * check_partial_indexes *		Check each partial index of the relation, and mark it predOK or not *		depending on whether the predicate is satisfied for this query. */voidcheck_partial_indexes(PlannerInfo *root, RelOptInfo *rel){	List	   *restrictinfo_list = rel->baserestrictinfo;	ListCell   *ilist;	/*	 * Note: if Postgres tried to optimize queries by forming equivalence	 * classes over equi-joined attributes (i.e., if it recognized that a	 * qualification such as "where a.b=c.d and a.b=5" could make use of an	 * index on c.d), then we could use that equivalence class info here with	 * joininfo lists to do more complete tests for the usability of a partial	 * index.  For now, the test only uses restriction clauses (those in	 * baserestrictinfo). --Nels, Dec '92	 *	 * XXX as of 7.1, equivalence class info *is* available.  Consider	 * improving this code as foreseen by Nels.	 */	foreach(ilist, rel->indexlist)	{		IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);		if (index->indpred == NIL)			continue;			/* ignore non-partial indexes */		index->predOK = predicate_implied_by(index->indpred,											 restrictinfo_list);	}}/**************************************************************************** *				----  ROUTINES TO CHECK JOIN CLAUSES  ---- ****************************************************************************//* * indexable_outerrelids *	  Finds all other relids that participate in any indexable join clause *	  for the specified table.	Returns a set of relids. */static Relidsindexable_outerrelids(RelOptInfo *rel){	Relids		outer_relids = NULL;	ListCell   *l;	/*	 * Examine each joinclause in the joininfo list to see if it matches any	 * key of any index.  If so, add the clause's other rels to the result.	 */	foreach(l, rel->joininfo)	{		RestrictInfo *joininfo = (RestrictInfo *) lfirst(l);		Relids		other_rels;		other_rels = bms_difference(joininfo->required_relids, rel->relids);		if (matches_any_index(joininfo, rel, other_rels))			outer_relids = bms_join(outer_relids, other_rels);		else			bms_free(other_rels);	}	return outer_relids;}/* * matches_any_index *	  Workhorse for indexable_outerrelids: see if a joinclause can be *	  matched to any index of the given rel. */static boolmatches_any_index(RestrictInfo *rinfo, RelOptInfo *rel, Relids outer_relids){	ListCell   *l;	Assert(IsA(rinfo, RestrictInfo));	if (restriction_is_or_clause(rinfo))	{		foreach(l, ((BoolExpr *) rinfo->orclause)->args)		{			Node	   *orarg = (Node *) lfirst(l);			/* OR arguments should be ANDs or sub-RestrictInfos */			if (and_clause(orarg))			{				ListCell   *j;				/* Recurse to examine AND items and sub-ORs */				foreach(j, ((BoolExpr *) orarg)->args)				{					RestrictInfo *arinfo = (RestrictInfo *) lfirst(j);					if (matches_any_index(arinfo, rel, outer_relids))						return true;				}			}			else			{				/* Recurse to examine simple clause */				Assert(IsA(orarg, RestrictInfo));				Assert(!restriction_is_or_clause((RestrictInfo *) orarg));				if (matches_any_index((RestrictInfo *) orarg, rel,									  outer_relids))					return true;			}		}		return false;	}	/* Normal case for a simple restriction clause */	foreach(l, rel->indexlist)	{		IndexOptInfo *index = (IndexOptInfo *) lfirst(l);		int			indexcol = 0;		Oid		   *classes = index->classlist;		do		{			Oid			curClass = classes[0];			if (match_clause_to_indexcol(index,										 indexcol,										 curClass,										 rinfo,										 outer_relids))				return true;			indexcol++;			classes++;		} while (!DoneMatchingIndexKeys(classes));	}	return false;}/* * best_inner_indexscan *	  Finds the best available inner indexscan for a nestloop join *	  with the given rel on the inside and the given outer_relids outside. *	  May return NULL if there are no possible inner indexscans. * * We ignore ordering considerations (since a nestloop's inner scan's order * is uninteresting).  Also, we consider only total cost when deciding which * of two possible paths is better --- this assumes that all indexpaths have * negligible startup cost.  (True today, but someday we might have to think * harder.)  Therefore, there is only one dimension of comparison and so it's * sufficient to return a single "best" path. */Path *best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,					 Relids outer_relids, JoinType jointype){	Path	   *cheapest;	bool		isouterjoin;	List	   *clause_list;	List	   *indexpaths;	List	   *bitindexpaths;	ListCell   *l;	InnerIndexscanInfo *info;	MemoryContext oldcontext;	/*	 * Nestloop only supports inner, left, and IN joins.	 */	switch (jointype)	{		case JOIN_INNER:		case JOIN_IN:		case JOIN_UNIQUE_OUTER:			isouterjoin = false;			break;		case JOIN_LEFT:			isouterjoin = true;			break;		default:			return NULL;	}	/*	 * If there are no indexable joinclauses for this rel, exit quickly.	 */	if (bms_is_empty(rel->index_outer_relids))		return NULL;	/*	 * Otherwise, we have to do path selection in the memory context of the	 * given rel, so that any created path can be safely attached to the rel's	 * cache of best inner paths.  (This is not currently an issue for normal	 * planning, but it is an issue for GEQO planning.)	 */	oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(rel));	/*	 * Intersect the given outer_relids with index_outer_relids to find the	 * set of outer relids actually relevant for this rel. If there are none,	 * again we can fail immediately.	 */	outer_relids = bms_intersect(rel->index_outer_relids, outer_relids);	if (bms_is_empty(outer_relids))	{		bms_free(outer_relids);		MemoryContextSwitchTo(oldcontext);		return NULL;	}	/*	 * Look to see if we already computed the result for this set of relevant	 * outerrels.  (We include the isouterjoin status in the cache lookup key	 * for safety.	In practice I suspect this is not necessary because it	 * should always be the same for a given innerrel.)	 */	foreach(l, rel->index_inner_paths)	{		info = (InnerIndexscanInfo *) lfirst(l);		if (bms_equal(info->other_relids, outer_relids) &&			info->isouterjoin == isouterjoin)		{			bms_free(outer_relids);			MemoryContextSwitchTo(oldcontext);			return info->best_innerpath;		}	}	/*	 * Find all the relevant restriction and join clauses.	 *	 * Note: because we include restriction clauses, we will find indexscans	 * that could be plain indexscans, ie, they don't require the join context	 * at all.  This may seem redundant, but we need to include those scans in	 * the input given to choose_bitmap_and() to be sure we find optimal AND	 * combinations of join and non-join scans.  The worst case is that we	 * might return a "best inner indexscan" that's really just a plain	 * indexscan, causing some redundant effort in joinpath.c.	 */	clause_list = find_clauses_for_join(root, rel, outer_relids, isouterjoin);	/*	 * Find all the index paths that are usable for this join, except for	 * stuff involving OR clauses.	 */	indexpaths = find_usable_indexes(root, rel,									 clause_list, NIL,									 false, true,									 outer_relids);	/*	 * Generate BitmapOrPaths for any suitable OR-clauses present in the	 * clause list.	 */	bitindexpaths = generate_bitmap_or_paths(root, rel,											 clause_list, NIL,											 true,											 outer_relids);	/*	 * Include the regular index paths in bitindexpaths.	 */	bitindexpaths = list_concat(bitindexpaths, list_copy(indexpaths));	/*	 * If we found anything usable, generate a BitmapHeapPath for the most

⌨️ 快捷键说明

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