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

📄 joinpath.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
			 * Always consider a nestloop join with this outer and			 * cheapest-total-cost inner.  When appropriate, also consider			 * using the materialized form of the cheapest inner, the			 * cheapest-startup-cost inner path, and the best innerjoin			 * indexpath.			 */			add_path(joinrel, (Path *)					 create_nestloop_path(root,										  joinrel,										  jointype,										  outerpath,										  inner_cheapest_total,										  restrictlist,										  merge_pathkeys));			if (matpath != NULL)				add_path(joinrel, (Path *)						 create_nestloop_path(root,											  joinrel,											  jointype,											  outerpath,											  matpath,											  restrictlist,											  merge_pathkeys));			if (inner_cheapest_startup != inner_cheapest_total)				add_path(joinrel, (Path *)						 create_nestloop_path(root,											  joinrel,											  jointype,											  outerpath,											  inner_cheapest_startup,											  restrictlist,											  merge_pathkeys));			if (bestinnerjoin != NULL)				add_path(joinrel, (Path *)						 create_nestloop_path(root,											  joinrel,											  jointype,											  outerpath,											  bestinnerjoin,											  restrictlist,											  merge_pathkeys));		}		/* Can't do anything else if outer path needs to be unique'd */		if (save_jointype == JOIN_UNIQUE_OUTER)			continue;		/* Look for useful mergeclauses (if any) */		mergeclauses = find_mergeclauses_for_pathkeys(root,													  outerpath->pathkeys,													  mergeclause_list);		/*		 * Done with this outer path if no chance for a mergejoin.		 *		 * Special corner case: for "x FULL JOIN y ON true", there will be no		 * join clauses at all.  Ordinarily we'd generate a clauseless		 * nestloop path, but since mergejoin is our only join type that		 * supports FULL JOIN, it's necessary to generate a clauseless		 * mergejoin path instead.		 */		if (mergeclauses == NIL)		{			if (jointype == JOIN_FULL)				 /* okay to try for mergejoin */ ;			else				continue;		}		if (useallclauses && list_length(mergeclauses) != list_length(mergeclause_list))			continue;		/* Compute the required ordering of the inner path */		innersortkeys = make_pathkeys_for_mergeclauses(root,													   mergeclauses,													   innerrel);		/*		 * Generate a mergejoin on the basis of sorting the cheapest inner.		 * Since a sort will be needed, only cheapest total cost matters. (But		 * create_mergejoin_path will do the right thing if		 * inner_cheapest_total is already correctly sorted.)		 */		add_path(joinrel, (Path *)				 create_mergejoin_path(root,									   joinrel,									   jointype,									   outerpath,									   inner_cheapest_total,									   restrictlist,									   merge_pathkeys,									   mergeclauses,									   NIL,									   innersortkeys));		/* Can't do anything else if inner path needs to be unique'd */		if (save_jointype == JOIN_UNIQUE_INNER)			continue;		/*		 * Look for presorted inner paths that satisfy the innersortkey list		 * --- or any truncation thereof, if we are allowed to build a		 * mergejoin using a subset of the merge clauses.  Here, we consider		 * both cheap startup cost and cheap total cost.  Ignore		 * inner_cheapest_total, since we already made a path with it.		 */		num_sortkeys = list_length(innersortkeys);		if (num_sortkeys > 1 && !useallclauses)			trialsortkeys = list_copy(innersortkeys);	/* need modifiable copy */		else			trialsortkeys = innersortkeys;		/* won't really truncate */		cheapest_startup_inner = NULL;		cheapest_total_inner = NULL;		for (sortkeycnt = num_sortkeys; sortkeycnt > 0; sortkeycnt--)		{			Path	   *innerpath;			List	   *newclauses = NIL;			/*			 * Look for an inner path ordered well enough for the first			 * 'sortkeycnt' innersortkeys.	NB: trialsortkeys list is modified			 * destructively, which is why we made a copy...			 */			trialsortkeys = list_truncate(trialsortkeys, sortkeycnt);			innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist,													   trialsortkeys,													   TOTAL_COST);			if (innerpath != NULL &&				innerpath != inner_cheapest_total &&				(cheapest_total_inner == NULL ||				 compare_path_costs(innerpath, cheapest_total_inner,									TOTAL_COST) < 0))			{				/* Found a cheap (or even-cheaper) sorted path */				/* Select the right mergeclauses, if we didn't already */				if (sortkeycnt < num_sortkeys)				{					newclauses =						find_mergeclauses_for_pathkeys(root,													   trialsortkeys,													   mergeclauses);					Assert(newclauses != NIL);				}				else					newclauses = mergeclauses;				add_path(joinrel, (Path *)						 create_mergejoin_path(root,											   joinrel,											   jointype,											   outerpath,											   innerpath,											   restrictlist,											   merge_pathkeys,											   newclauses,											   NIL,											   NIL));				cheapest_total_inner = innerpath;			}			/* Same on the basis of cheapest startup cost ... */			innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist,													   trialsortkeys,													   STARTUP_COST);			if (innerpath != NULL &&				innerpath != inner_cheapest_total &&				(cheapest_startup_inner == NULL ||				 compare_path_costs(innerpath, cheapest_startup_inner,									STARTUP_COST) < 0))			{				/* Found a cheap (or even-cheaper) sorted path */				if (innerpath != cheapest_total_inner)				{					/*					 * Avoid rebuilding clause list if we already made one;					 * saves memory in big join trees...					 */					if (newclauses == NIL)					{						if (sortkeycnt < num_sortkeys)						{							newclauses =								find_mergeclauses_for_pathkeys(root,															   trialsortkeys,															   mergeclauses);							Assert(newclauses != NIL);						}						else							newclauses = mergeclauses;					}					add_path(joinrel, (Path *)							 create_mergejoin_path(root,												   joinrel,												   jointype,												   outerpath,												   innerpath,												   restrictlist,												   merge_pathkeys,												   newclauses,												   NIL,												   NIL));				}				cheapest_startup_inner = innerpath;			}			/*			 * Don't consider truncated sortkeys if we need all clauses.			 */			if (useallclauses)				break;		}	}}/* * hash_inner_and_outer *	  Create hashjoin join paths by explicitly hashing both the outer and *	  inner keys of each available hash clause. * * 'joinrel' is the join relation * 'outerrel' is the outer join relation * 'innerrel' is the inner join relation * 'restrictlist' contains all of the RestrictInfo nodes for restriction *		clauses that apply to this join * 'jointype' is the type of join to do */static voidhash_inner_and_outer(PlannerInfo *root,					 RelOptInfo *joinrel,					 RelOptInfo *outerrel,					 RelOptInfo *innerrel,					 List *restrictlist,					 JoinType jointype){	bool		isouterjoin;	List	   *hashclauses;	ListCell   *l;	/*	 * Hashjoin only supports inner, left, and IN joins.	 */	switch (jointype)	{		case JOIN_INNER:		case JOIN_IN:		case JOIN_UNIQUE_OUTER:		case JOIN_UNIQUE_INNER:			isouterjoin = false;			break;		case JOIN_LEFT:			isouterjoin = true;			break;		default:			return;	}	/*	 * We need to build only one hashpath for any given pair of outer and	 * inner relations; all of the hashable clauses will be used as keys.	 *	 * Scan the join's restrictinfo list to find hashjoinable clauses that are	 * usable with this pair of sub-relations.	 */	hashclauses = NIL;	foreach(l, restrictlist)	{		RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);		if (!restrictinfo->can_join ||			restrictinfo->hashjoinoperator == InvalidOid)			continue;			/* not hashjoinable */		/*		 * If processing an outer join, only use its own join clauses for		 * hashing.  For inner joins we need not be so picky.		 */		if (isouterjoin && restrictinfo->is_pushed_down)			continue;		/*		 * Check if clause is usable with these input rels.		 */		if (bms_is_subset(restrictinfo->left_relids, outerrel->relids) &&			bms_is_subset(restrictinfo->right_relids, innerrel->relids))		{			/* righthand side is inner */		}		else if (bms_is_subset(restrictinfo->left_relids, innerrel->relids) &&				 bms_is_subset(restrictinfo->right_relids, outerrel->relids))		{			/* lefthand side is inner */		}		else			continue;			/* no good for these input relations */		hashclauses = lappend(hashclauses, restrictinfo);	}	/* If we found any usable hashclauses, make a path */	if (hashclauses)	{		/*		 * We consider both the cheapest-total-cost and cheapest-startup-cost		 * outer paths.  There's no need to consider any but the		 * cheapest-total-cost inner path, however.		 */		Path	   *cheapest_startup_outer = outerrel->cheapest_startup_path;		Path	   *cheapest_total_outer = outerrel->cheapest_total_path;		Path	   *cheapest_total_inner = innerrel->cheapest_total_path;		/* Unique-ify if need be */		if (jointype == JOIN_UNIQUE_OUTER)		{			cheapest_total_outer = (Path *)				create_unique_path(root, outerrel, cheapest_total_outer);			cheapest_startup_outer = cheapest_total_outer;			jointype = JOIN_INNER;		}		else if (jointype == JOIN_UNIQUE_INNER)		{			cheapest_total_inner = (Path *)				create_unique_path(root, innerrel, cheapest_total_inner);			jointype = JOIN_INNER;		}		add_path(joinrel, (Path *)				 create_hashjoin_path(root,									  joinrel,									  jointype,									  cheapest_total_outer,									  cheapest_total_inner,									  restrictlist,									  hashclauses));		if (cheapest_startup_outer != cheapest_total_outer)			add_path(joinrel, (Path *)					 create_hashjoin_path(root,										  joinrel,										  jointype,										  cheapest_startup_outer,										  cheapest_total_inner,										  restrictlist,										  hashclauses));	}}/* * select_mergejoin_clauses *	  Select mergejoin clauses that are usable for a particular join. *	  Returns a list of RestrictInfo nodes for those clauses. * * We examine each restrictinfo clause known for the join to see * if it is mergejoinable and involves vars from the two sub-relations * currently of interest. */static List *select_mergejoin_clauses(RelOptInfo *joinrel,						 RelOptInfo *outerrel,						 RelOptInfo *innerrel,						 List *restrictlist,						 JoinType jointype){	List	   *result_list = NIL;	bool		isouterjoin = IS_OUTER_JOIN(jointype);	bool		have_nonmergeable_joinclause = false;	ListCell   *l;	foreach(l, restrictlist)	{		RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);		/*		 * If processing an outer join, only use its own join clauses in the		 * merge.  For inner joins we can use pushed-down clauses too. (Note:		 * we don't set have_nonmergeable_joinclause here because pushed-down		 * clauses will become otherquals not joinquals.)		 */		if (isouterjoin && restrictinfo->is_pushed_down)			continue;		if (!restrictinfo->can_join ||			restrictinfo->mergejoinoperator == InvalidOid)		{			have_nonmergeable_joinclause = true;			continue;			/* not mergejoinable */		}		/*		 * Check if clause is usable with these input rels.  All the vars		 * needed on each side of the clause must be available from one or the		 * other of the input rels.		 */		if (bms_is_subset(restrictinfo->left_relids, outerrel->relids) &&			bms_is_subset(restrictinfo->right_relids, innerrel->relids))		{			/* righthand side is inner */		}		else if (bms_is_subset(restrictinfo->left_relids, innerrel->relids) &&				 bms_is_subset(restrictinfo->right_relids, outerrel->relids))		{			/* lefthand side is inner */		}		else		{			have_nonmergeable_joinclause = true;			continue;			/* no good for these input relations */		}		result_list = lcons(restrictinfo, result_list);	}	/*	 * If it is a right/full join then *all* the explicit join clauses must be	 * mergejoinable, else the executor will fail. If we are asked for a right	 * join then just return NIL to indicate no mergejoin is possible (we can	 * handle it as a left join instead). If we are asked for a full join then	 * emit an error, because there is no fallback.	 */	if (have_nonmergeable_joinclause)	{		switch (jointype)		{			case JOIN_RIGHT:				return NIL;		/* not mergejoinable */			case JOIN_FULL:				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("FULL JOIN is only supported with merge-joinable join conditions")));				break;			default:				/* otherwise, it's OK to have nonmergeable join quals */				break;		}	}	return result_list;}

⌨️ 快捷键说明

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