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

📄 pathkeys.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
		return NIL;	/*	 * This used to be quite a complex bit of code, but now that all pathkey	 * sublists start out life canonicalized, we don't have to do a darn thing	 * here!  The inner-rel vars we used to need to add are *already* part of	 * the outer pathkey!	 *	 * We do, however, need to truncate the pathkeys list, since it may	 * contain pathkeys that were useful for forming this joinrel but are	 * uninteresting to higher levels.	 */	return truncate_useless_pathkeys(root, joinrel, outer_pathkeys);}/**************************************************************************** *		PATHKEYS AND SORT CLAUSES ****************************************************************************//* * make_pathkeys_for_sortclauses *		Generate a pathkeys list that represents the sort order specified *		by a list of SortClauses (GroupClauses will work too!) * * NB: the result is NOT in canonical form, but must be passed through * canonicalize_pathkeys() before it can be used for comparisons or * labeling relation sort orders.  (We do things this way because * grouping_planner needs to be able to construct requested pathkeys * before the pathkey equivalence sets have been created for the query.) * * 'sortclauses' is a list of SortClause or GroupClause nodes * 'tlist' is the targetlist to find the referenced tlist entries in */List *make_pathkeys_for_sortclauses(List *sortclauses,							  List *tlist){	List	   *pathkeys = NIL;	ListCell   *l;	foreach(l, sortclauses)	{		SortClause *sortcl = (SortClause *) lfirst(l);		Node	   *sortkey;		PathKeyItem *pathkey;		sortkey = get_sortgroupclause_expr(sortcl, tlist);		pathkey = makePathKeyItem(sortkey, sortcl->sortop, true);		/*		 * The pathkey becomes a one-element sublist, for now;		 * canonicalize_pathkeys() might replace it with a longer sublist		 * later.		 */		pathkeys = lappend(pathkeys, list_make1(pathkey));	}	return pathkeys;}/**************************************************************************** *		PATHKEYS AND MERGECLAUSES ****************************************************************************//* * cache_mergeclause_pathkeys *		Make the cached pathkeys valid in a mergeclause restrictinfo. * * RestrictInfo contains fields in which we may cache the result * of looking up the canonical pathkeys for the left and right sides * of the mergeclause.	(Note that in normal cases they will be the * same, but not if the mergeclause appears above an OUTER JOIN.) * This is a worthwhile savings because these routines will be invoked * many times when dealing with a many-relation query. * * We have to be careful that the cached values are palloc'd in the same * context the RestrictInfo node itself is in.	This is not currently a * problem for normal planning, but it is an issue for GEQO planning. */voidcache_mergeclause_pathkeys(PlannerInfo *root, RestrictInfo *restrictinfo){	Node	   *key;	PathKeyItem *item;	MemoryContext oldcontext;	Assert(restrictinfo->mergejoinoperator != InvalidOid);	if (restrictinfo->left_pathkey == NIL)	{		oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(restrictinfo));		key = get_leftop(restrictinfo->clause);		item = makePathKeyItem(key, restrictinfo->left_sortop, false);		restrictinfo->left_pathkey = make_canonical_pathkey(root, item);		MemoryContextSwitchTo(oldcontext);	}	if (restrictinfo->right_pathkey == NIL)	{		oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(restrictinfo));		key = get_rightop(restrictinfo->clause);		item = makePathKeyItem(key, restrictinfo->right_sortop, false);		restrictinfo->right_pathkey = make_canonical_pathkey(root, item);		MemoryContextSwitchTo(oldcontext);	}}/* * find_mergeclauses_for_pathkeys *	  This routine attempts to find a set of mergeclauses that can be *	  used with a specified ordering for one of the input relations. *	  If successful, it returns a list of mergeclauses. * * 'pathkeys' is a pathkeys list showing the ordering of an input path. *			It doesn't matter whether it is for the inner or outer path. * 'restrictinfos' is a list of mergejoinable restriction clauses for the *			join relation being formed. * * The result is NIL if no merge can be done, else a maximal list of * usable mergeclauses (represented as a list of their restrictinfo nodes). * * XXX Ideally we ought to be considering context, ie what path orderings * are available on the other side of the join, rather than just making * an arbitrary choice among the mergeclauses that will work for this side * of the join. */List *find_mergeclauses_for_pathkeys(PlannerInfo *root,							   List *pathkeys,							   List *restrictinfos){	List	   *mergeclauses = NIL;	ListCell   *i;	/* make sure we have pathkeys cached in the clauses */	foreach(i, restrictinfos)	{		RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i);		cache_mergeclause_pathkeys(root, restrictinfo);	}	foreach(i, pathkeys)	{		List	   *pathkey = (List *) lfirst(i);		List	   *matched_restrictinfos = NIL;		ListCell   *j;		/*		 * We can match a pathkey against either left or right side of any		 * mergejoin clause.  (We examine both sides since we aren't told if		 * the given pathkeys are for inner or outer input path; no confusion		 * is possible.)  Furthermore, if there are multiple matching clauses,		 * take them all.  In plain inner-join scenarios we expect only one		 * match, because redundant-mergeclause elimination will have removed		 * any redundant mergeclauses from the input list. However, in		 * outer-join scenarios there might be multiple matches. An example is		 *		 * select * from a full join b on a.v1 = b.v1 and a.v2 = b.v2 and a.v1		 * = b.v2;		 *		 * Given the pathkeys ((a.v1), (a.v2)) it is okay to return all three		 * clauses (in the order a.v1=b.v1, a.v1=b.v2, a.v2=b.v2) and indeed		 * we *must* do so or we will be unable to form a valid plan.		 */		foreach(j, restrictinfos)		{			RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(j);			/*			 * We can compare canonical pathkey sublists by simple pointer			 * equality; see compare_pathkeys.			 */			if ((pathkey == restrictinfo->left_pathkey ||				 pathkey == restrictinfo->right_pathkey) &&				!list_member_ptr(mergeclauses, restrictinfo))			{				matched_restrictinfos = lappend(matched_restrictinfos,												restrictinfo);			}		}		/*		 * If we didn't find a mergeclause, we're done --- any additional		 * sort-key positions in the pathkeys are useless.	(But we can still		 * mergejoin if we found at least one mergeclause.)		 */		if (matched_restrictinfos == NIL)			break;		/*		 * If we did find usable mergeclause(s) for this sort-key position,		 * add them to result list.		 */		mergeclauses = list_concat(mergeclauses, matched_restrictinfos);	}	return mergeclauses;}/* * make_pathkeys_for_mergeclauses *	  Builds a pathkey list representing the explicit sort order that *	  must be applied to a path in order to make it usable for the *	  given mergeclauses. * * 'mergeclauses' is a list of RestrictInfos for mergejoin clauses *			that will be used in a merge join. * 'rel' is the relation the pathkeys will apply to (ie, either the inner *			or outer side of the proposed join rel). * * Returns a pathkeys list that can be applied to the indicated relation. * * Note that it is not this routine's job to decide whether sorting is * actually needed for a particular input path.  Assume a sort is necessary; * just make the keys, eh? */List *make_pathkeys_for_mergeclauses(PlannerInfo *root,							   List *mergeclauses,							   RelOptInfo *rel){	List	   *pathkeys = NIL;	ListCell   *l;	foreach(l, mergeclauses)	{		RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);		List	   *pathkey;		cache_mergeclause_pathkeys(root, restrictinfo);		if (bms_is_subset(restrictinfo->left_relids, rel->relids))		{			/* Rel is left side of mergeclause */			pathkey = restrictinfo->left_pathkey;		}		else if (bms_is_subset(restrictinfo->right_relids, rel->relids))		{			/* Rel is right side of mergeclause */			pathkey = restrictinfo->right_pathkey;		}		else		{			elog(ERROR, "could not identify which side of mergeclause to use");			pathkey = NIL;		/* keep compiler quiet */		}		/*		 * When we are given multiple merge clauses, it's possible that some		 * clauses refer to the same vars as earlier clauses. There's no		 * reason for us to specify sort keys like (A,B,A) when (A,B) will do		 * --- and adding redundant sort keys makes add_path think that this		 * sort order is different from ones that are really the same, so		 * don't do it.  Since we now have a canonicalized pathkey, a simple		 * ptrMember test is sufficient to detect redundant keys.		 */		pathkeys = list_append_unique_ptr(pathkeys, pathkey);	}	return pathkeys;}/**************************************************************************** *		PATHKEY USEFULNESS CHECKS * * We only want to remember as many of the pathkeys of a path as have some * potential use, either for subsequent mergejoins or for meeting the query's * requested output ordering.  This ensures that add_path() won't consider * a path to have a usefully different ordering unless it really is useful. * These routines check for usefulness of given pathkeys. ****************************************************************************//* * pathkeys_useful_for_merging *		Count the number of pathkeys that may be useful for mergejoins *		above the given relation (by looking at its joininfo list). * * We consider a pathkey potentially useful if it corresponds to the merge * ordering of either side of any joinclause for the rel.  This might be * overoptimistic, since joinclauses that require different other relations * might never be usable at the same time, but trying to be exact is likely * to be more trouble than it's worth. */intpathkeys_useful_for_merging(PlannerInfo *root, RelOptInfo *rel, List *pathkeys){	int			useful = 0;	ListCell   *i;	foreach(i, pathkeys)	{		List	   *pathkey = (List *) lfirst(i);		bool		matched = false;		ListCell   *j;		foreach(j, rel->joininfo)		{			RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(j);			if (restrictinfo->mergejoinoperator == InvalidOid)				continue;			cache_mergeclause_pathkeys(root, restrictinfo);			/*			 * We can compare canonical pathkey sublists by simple pointer			 * equality; see compare_pathkeys.			 */			if (pathkey == restrictinfo->left_pathkey ||				pathkey == restrictinfo->right_pathkey)			{				matched = true;				break;			}		}		/*		 * If we didn't find a mergeclause, we're done --- any additional		 * sort-key positions in the pathkeys are useless.	(But we can still		 * mergejoin if we found at least one mergeclause.)		 */		if (matched)			useful++;		else			break;	}	return useful;}/* * pathkeys_useful_for_ordering *		Count the number of pathkeys that are useful for meeting the *		query's requested output ordering. * * Unlike merge pathkeys, this is an all-or-nothing affair: it does us * no good to order by just the first key(s) of the requested ordering. * So the result is always either 0 or list_length(root->query_pathkeys). */intpathkeys_useful_for_ordering(PlannerInfo *root, List *pathkeys){	if (root->query_pathkeys == NIL)		return 0;				/* no special ordering requested */	if (pathkeys == NIL)		return 0;				/* unordered path */	if (pathkeys_contained_in(root->query_pathkeys, pathkeys))	{		/* It's useful ... or at least the first N keys are */		return list_length(root->query_pathkeys);	}	return 0;					/* path ordering not useful */}/* * truncate_useless_pathkeys *		Shorten the given pathkey list to just the useful pathkeys. */List *truncate_useless_pathkeys(PlannerInfo *root,						  RelOptInfo *rel,						  List *pathkeys){	int			nuseful;	int			nuseful2;	nuseful = pathkeys_useful_for_merging(root, rel, pathkeys);	nuseful2 = pathkeys_useful_for_ordering(root, pathkeys);	if (nuseful2 > nuseful)		nuseful = nuseful2;	/*	 * Note: not safe to modify input list destructively, but we can avoid	 * copying the list if we're not actually going to change it	 */	if (nuseful == list_length(pathkeys))		return pathkeys;	else		return list_truncate(list_copy(pathkeys), nuseful);}

⌨️ 快捷键说明

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