indxpath.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,070 行 · 第 1/5 页

C
2,070
字号
	/* Set up a dummy BitmapAndPath */	apath.path.type = T_BitmapAndPath;	apath.path.parent = rel;	apath.bitmapquals = paths;	cost_bitmap_and_node(&apath, root);	/* Now we can do cost_bitmap_heap_scan */	cost_bitmap_heap_scan(&bpath, root, rel, (Path *) &apath, outer_rel);	return bpath.total_cost;}/* * classify_index_clause_usage *		Construct a PathClauseUsage struct describing the WHERE clauses and *		index predicate clauses used by the given indexscan path. *		We consider two clauses the same if they are equal(). * * At some point we might want to migrate this info into the Path data * structure proper, but for the moment it's only needed within * choose_bitmap_and(). * * *clauselist is used and expanded as needed to identify all the distinct * clauses seen across successive calls.  Caller must initialize it to NIL * before first call of a set. */static PathClauseUsage *classify_index_clause_usage(Path *path, List **clauselist){	PathClauseUsage *result;	Bitmapset  *clauseids;	ListCell   *lc;	result = (PathClauseUsage *) palloc(sizeof(PathClauseUsage));	result->path = path;	/* Recursively find the quals and preds used by the path */	result->quals = NIL;	result->preds = NIL;	find_indexpath_quals(path, &result->quals, &result->preds);	/* Build up a bitmapset representing the quals and preds */	clauseids = NULL;	foreach(lc, result->quals)	{		Node	   *node = (Node *) lfirst(lc);		clauseids = bms_add_member(clauseids,								   find_list_position(node, clauselist));	}	foreach(lc, result->preds)	{		Node	   *node = (Node *) lfirst(lc);		clauseids = bms_add_member(clauseids,								   find_list_position(node, clauselist));	}	result->clauseids = clauseids;	return result;}/* * find_indexpath_quals * * Given the Path structure for a plain or bitmap indexscan, extract lists * of all the indexquals and index predicate conditions used in the Path. * These are appended to the initial contents of *quals and *preds (hence * caller should initialize those to NIL). * * This is sort of a simplified version of make_restrictinfo_from_bitmapqual; * here, we are not trying to produce an accurate representation of the AND/OR * semantics of the Path, but just find out all the base conditions used. * * The result lists contain pointers to the expressions used in the Path, * but all the list cells are freshly built, so it's safe to destructively * modify the lists (eg, by concat'ing with other lists). */static voidfind_indexpath_quals(Path *bitmapqual, List **quals, List **preds){	if (IsA(bitmapqual, BitmapAndPath))	{		BitmapAndPath *apath = (BitmapAndPath *) bitmapqual;		ListCell   *l;		foreach(l, apath->bitmapquals)		{			find_indexpath_quals((Path *) lfirst(l), quals, preds);		}	}	else if (IsA(bitmapqual, BitmapOrPath))	{		BitmapOrPath *opath = (BitmapOrPath *) bitmapqual;		ListCell   *l;		foreach(l, opath->bitmapquals)		{			find_indexpath_quals((Path *) lfirst(l), quals, preds);		}	}	else if (IsA(bitmapqual, IndexPath))	{		IndexPath  *ipath = (IndexPath *) bitmapqual;		*quals = list_concat(*quals, get_actual_clauses(ipath->indexclauses));		*preds = list_concat(*preds, list_copy(ipath->indexinfo->indpred));	}	else		elog(ERROR, "unrecognized node type: %d", nodeTag(bitmapqual));}/* * find_list_position *		Return the given node's position (counting from 0) in the given *		list of nodes.	If it's not equal() to any existing list member, *		add it at the end, and return that position. */static intfind_list_position(Node *node, List **nodelist){	int			i;	ListCell   *lc;	i = 0;	foreach(lc, *nodelist)	{		Node	   *oldnode = (Node *) lfirst(lc);		if (equal(node, oldnode))			return i;		i++;	}	*nodelist = lappend(*nodelist, node);	return i;}/**************************************************************************** *				----  ROUTINES TO CHECK RESTRICTIONS  ---- ****************************************************************************//* * group_clauses_by_indexkey *	  Find restriction clauses that can be used with an index. * * Returns a list of sublists of RestrictInfo nodes for clauses that can be * used with this index.  Each sublist contains clauses that can be used * with one index key (in no particular order); the top list is ordered by * index key.  (This is depended on by expand_indexqual_conditions().) * * We can use clauses from either the current clauses or outer_clauses lists, * but *found_clause is set TRUE only if we used at least one clause from * the "current clauses" list.	See find_usable_indexes() for motivation. * * outer_relids determines what Vars will be allowed on the other side * of a possible index qual; see match_clause_to_indexcol(). * * 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used. * When it's SAOP_REQUIRE, *found_clause is set TRUE only if we used at least * one ScalarArrayOpExpr from the current clauses list. * * If the index has amoptionalkey = false, we give up and return NIL when * there are no restriction clauses matching the first index key.  Otherwise, * we return NIL if there are no restriction clauses matching any index key. * A non-NIL result will have one (possibly empty) sublist for each index key. * * Example: given an index on (A,B,C), we would return ((C1 C2) () (C3 C4)) * if we find that clauses C1 and C2 use column A, clauses C3 and C4 use * column C, and no clauses use column B. * * Note: in some circumstances we may find the same RestrictInfos coming * from multiple places.  Defend against redundant outputs by using * list_append_unique_ptr (pointer equality should be good enough). */List *group_clauses_by_indexkey(IndexOptInfo *index,						  List *clauses, List *outer_clauses,						  Relids outer_relids,						  SaOpControl saop_control,						  bool *found_clause){	List	   *clausegroup_list = NIL;	bool		found_outer_clause = false;	int			indexcol = 0;	Oid		   *families = index->opfamily;	*found_clause = false;		/* default result */	if (clauses == NIL && outer_clauses == NIL)		return NIL;				/* cannot succeed */	do	{		Oid			curFamily = families[0];		List	   *clausegroup = NIL;		ListCell   *l;		/* check the current clauses */		foreach(l, clauses)		{			RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);			Assert(IsA(rinfo, RestrictInfo));			if (match_clause_to_indexcol(index,										 indexcol,										 curFamily,										 rinfo,										 outer_relids,										 saop_control))			{				clausegroup = list_append_unique_ptr(clausegroup, rinfo);				if (saop_control != SAOP_REQUIRE ||					IsA(rinfo->clause, ScalarArrayOpExpr))					*found_clause = true;			}		}		/* check the outer clauses */		foreach(l, outer_clauses)		{			RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);			Assert(IsA(rinfo, RestrictInfo));			if (match_clause_to_indexcol(index,										 indexcol,										 curFamily,										 rinfo,										 outer_relids,										 saop_control))			{				clausegroup = list_append_unique_ptr(clausegroup, rinfo);				found_outer_clause = true;			}		}		/*		 * If no clauses match this key, check for amoptionalkey restriction.		 */		if (clausegroup == NIL && !index->amoptionalkey && indexcol == 0)			return NIL;		clausegroup_list = lappend(clausegroup_list, clausegroup);		indexcol++;		families++;	} while (!DoneMatchingIndexKeys(families));	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 family 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. * *	  It is also possible to match RowCompareExpr clauses to indexes (but *	  currently, only btree indexes handle this).  In this routine we will *	  report a match if the first column of the row comparison matches the *	  target index column.	This is sufficient to guarantee that some index *	  condition can be constructed from the RowCompareExpr --- whether the *	  remaining columns match the index too is considered in *	  expand_indexqual_rowcompare(). * *	  It is also possible to match ScalarArrayOpExpr clauses to indexes, when *	  the clause is of the form "indexkey op ANY (arrayconst)".  Since the *	  executor can only handle these in the context of bitmap index scans, *	  our caller specifies whether to allow these or not. * *	  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). * 'opfamily' is the corresponding operator family. * 'rinfo' is the clause to be tested (as a RestrictInfo node). * 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used. * * 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 opfamily,						 RestrictInfo *rinfo,						 Relids outer_relids,						 SaOpControl saop_control){	Expr	   *clause = rinfo->clause;	Node	   *leftop,			   *rightop;	Relids		left_relids;	Relids		right_relids;	Oid			expr_op;	bool		plain_op;	/*	 * Never match pseudoconstants to indexes.	(Normally this could not	 * happen anyway, since a pseudoconstant clause couldn't contain a Var,	 * but what if someone builds an expression index on a constant? It's not	 * totally unreasonable to do so with a partial index, either.)	 */	if (rinfo->pseudoconstant)		return false;	/* First check for boolean-index cases. */	if (IsBooleanOpfamily(opfamily))	{		if (match_boolean_index_clause((Node *) clause, indexcol, index))			return true;	}	/*	 * Clause must be a binary opclause, or possibly a ScalarArrayOpExpr	 * (which is always binary, by definition).  Or it could be a	 * RowCompareExpr, which we pass off to match_rowcompare_to_indexcol().	 * Or, if the index supports it, we can handle IS NULL clauses.	 */	if (is_opclause(clause))	{		leftop = get_leftop(clause);		rightop = get_rightop(clause);		if (!leftop || !rightop)			return false;		left_relids = rinfo->left_relids;		right_relids = rinfo->right_relids;		expr_op = ((OpExpr *) clause)->opno;		plain_op = true;	}	else if (saop_control != SAOP_FORBID &&			 clause && IsA(clause, ScalarArrayOpExpr))	{		ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;		/* We only accept ANY clauses, not ALL */		if (!saop->useOr)			return false;		leftop = (Node *) linitial(saop->args);		rightop = (Node *) lsecond(saop->args);		left_relids = NULL;		/* not actually needed */		right_relids = pull_varnos(rightop);		expr_op = saop->opno;		plain_op = false;	}	else if (clause && IsA(clause, RowCompareExpr))	{		return match_rowcompare_to_indexcol(index, indexcol, opfamily,											(RowCompareExpr *) clause,											outer_relids);	}	else if (index->amsearchnulls && IsA(clause, NullTest))	{		NullTest   *nt = (NullTest *) clause;		if (nt->nulltesttype == IS_NULL &&			match_index_to_operand((Node *) nt->arg, indexcol, index))			return true;		return false;	}	else		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(right_relids, outer_relids) &&		!contain_volatile_functions(rightop))	{		if (is_indexable_operator(expr_op, opfamily, true))			return true;		/*

⌨️ 快捷键说明

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