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

📄 joinrels.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * joinrels.c *	  Routines to determine which relations should be joined * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.76.2.1 2005/11/22 18:23:10 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "optimizer/joininfo.h"#include "optimizer/pathnode.h"#include "optimizer/paths.h"static List *make_rels_by_clause_joins(PlannerInfo *root,						  RelOptInfo *old_rel,						  ListCell *other_rels);static List *make_rels_by_clauseless_joins(PlannerInfo *root,							  RelOptInfo *old_rel,							  ListCell *other_rels);static bool is_inside_IN(PlannerInfo *root, RelOptInfo *rel);/* * make_rels_by_joins *	  Consider ways to produce join relations containing exactly 'level' *	  jointree items.  (This is one step of the dynamic-programming method *	  embodied in make_one_rel_by_joins.)  Join rel nodes for each feasible *	  combination of lower-level rels are created and returned in a list. *	  Implementation paths are created for each such joinrel, too. * * level: level of rels we want to make this time. * joinrels[j], 1 <= j < level, is a list of rels containing j items. */List *make_rels_by_joins(PlannerInfo *root, int level, List **joinrels){	List	   *result_rels = NIL;	List	   *new_rels;	ListCell   *r;	int			k;	/*	 * First, consider left-sided and right-sided plans, in which rels of	 * exactly level-1 member relations are joined against initial relations.	 * We prefer to join using join clauses, but if we find a rel of level-1	 * members that has no join clauses, we will generate Cartesian-product	 * joins against all initial rels not already contained in it.	 *	 * In the first pass (level == 2), we try to join each initial rel to each	 * initial rel that appears later in joinrels[1].  (The mirror-image joins	 * are handled automatically by make_join_rel.)  In later passes, we try	 * to join rels of size level-1 from joinrels[level-1] to each initial rel	 * in joinrels[1].	 */	foreach(r, joinrels[level - 1])	{		RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);		ListCell   *other_rels;		if (level == 2)			other_rels = lnext(r);		/* only consider remaining initial										 * rels */		else			other_rels = list_head(joinrels[1]);		/* consider all initial														 * rels */		if (old_rel->joininfo != NIL)		{			/*			 * Note that if all available join clauses for this rel require			 * more than one other rel, we will fail to make any joins against			 * it here.  In most cases that's OK; it'll be considered by			 * "bushy plan" join code in a higher-level pass where we have			 * those other rels collected into a join rel.			 */			new_rels = make_rels_by_clause_joins(root,												 old_rel,												 other_rels);			/*			 * An exception occurs when there is a clauseless join inside an			 * IN (sub-SELECT) construct.  Here, the members of the subselect			 * all have join clauses (against the stuff outside the IN), but			 * they *must* be joined to each other before we can make use of			 * those join clauses.	So do the clauseless join bit.			 *			 * See also the last-ditch case below.			 */			if (new_rels == NIL && is_inside_IN(root, old_rel))				new_rels = make_rels_by_clauseless_joins(root,														 old_rel,														 other_rels);		}		else		{			/*			 * Oops, we have a relation that is not joined to any other			 * relation.  Cartesian product time.			 */			new_rels = make_rels_by_clauseless_joins(root,													 old_rel,													 other_rels);		}		/*		 * At levels above 2 we will generate the same joined relation in		 * multiple ways --- for example (a join b) join c is the same		 * RelOptInfo as (b join c) join a, though the second case will add a		 * different set of Paths to it.  To avoid making extra work for		 * subsequent passes, do not enter the same RelOptInfo into our output		 * list multiple times.		 */		result_rels = list_concat_unique_ptr(result_rels, new_rels);	}	/*	 * Now, consider "bushy plans" in which relations of k initial rels are	 * joined to relations of level-k initial rels, for 2 <= k <= level-2.	 *	 * We only consider bushy-plan joins for pairs of rels where there is a	 * suitable join clause, in order to avoid unreasonable growth of planning	 * time.	 */	for (k = 2;; k++)	{		int			other_level = level - k;		/*		 * Since make_join_rel(x, y) handles both x,y and y,x cases, we only		 * need to go as far as the halfway point.		 */		if (k > other_level)			break;		foreach(r, joinrels[k])		{			RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);			ListCell   *other_rels;			ListCell   *r2;			if (old_rel->joininfo == NIL)				continue;		/* we ignore clauseless joins here */			if (k == other_level)				other_rels = lnext(r);	/* only consider remaining rels */			else				other_rels = list_head(joinrels[other_level]);			for_each_cell(r2, other_rels)			{				RelOptInfo *new_rel = (RelOptInfo *) lfirst(r2);				if (!bms_overlap(old_rel->relids, new_rel->relids))				{					/*					 * OK, we can build a rel of the right level from this					 * pair of rels.  Do so if there is at least one usable					 * join clause.					 */					if (have_relevant_joinclause(old_rel, new_rel))					{						RelOptInfo *jrel;						jrel = make_join_rel(root, old_rel, new_rel,											 JOIN_INNER);						/* Avoid making duplicate entries ... */						if (jrel)							result_rels = list_append_unique_ptr(result_rels,																 jrel);					}				}			}		}	}	/*	 * Last-ditch effort: if we failed to find any usable joins so far, force	 * a set of cartesian-product joins to be generated.  This handles the	 * special case where all the available rels have join clauses but we	 * cannot use any of the joins yet.  An example is	 *	 * SELECT * FROM a,b,c WHERE (a.f1 + b.f2 + c.f3) = 0;	 *	 * The join clause will be usable at level 3, but at level 2 we have no	 * choice but to make cartesian joins.	We consider only left-sided and	 * right-sided cartesian joins in this case (no bushy).	 */	if (result_rels == NIL)	{		/*		 * This loop is just like the first one, except we always call		 * make_rels_by_clauseless_joins().		 */		foreach(r, joinrels[level - 1])		{			RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);			ListCell   *other_rels;			if (level == 2)				other_rels = lnext(r);	/* only consider remaining initial										 * rels */			else				other_rels = list_head(joinrels[1]);	/* consider all initial														 * rels */			new_rels = make_rels_by_clauseless_joins(root,													 old_rel,													 other_rels);			result_rels = list_concat_unique_ptr(result_rels, new_rels);		}		/*----------		 * When IN clauses are involved, there may be no legal way to make		 * an N-way join for some values of N.	For example consider		 *		 * SELECT ... FROM t1 WHERE		 *	 x IN (SELECT ... FROM t2,t3 WHERE ...) AND		 *	 y IN (SELECT ... FROM t4,t5 WHERE ...)		 *		 * We will flatten this query to a 5-way join problem, but there are		 * no 4-way joins that make_join_rel() will consider legal.  We have		 * to accept failure at level 4 and go on to discover a workable		 * bushy plan at level 5.		 *		 * However, if there are no IN clauses then make_join_rel() should		 * never fail, and so the following sanity check is useful.		 *----------		 */		if (result_rels == NIL && root->in_info_list == NIL)			elog(ERROR, "failed to build any %d-way joins", level);	}	return result_rels;}/* * make_rels_by_clause_joins *	  Build joins between the given relation 'old_rel' and other relations *	  that are mentioned within old_rel's joininfo list (i.e., relations *	  that participate in join clauses that 'old_rel' also participates in). *	  The join rel nodes are returned in a list. * * 'old_rel' is the relation entry for the relation to be joined * 'other_rels': the first cell in a linked list containing the other * rels to be considered for joining * * Currently, this is only used with initial rels in other_rels, but it * will work for joining to joinrels too. */static List *make_rels_by_clause_joins(PlannerInfo *root,						  RelOptInfo *old_rel,						  ListCell *other_rels){	List	   *result = NIL;	ListCell   *l;	for_each_cell(l, other_rels)	{		RelOptInfo *other_rel = (RelOptInfo *) lfirst(l);		if (!bms_overlap(old_rel->relids, other_rel->relids) &&			have_relevant_joinclause(old_rel, other_rel))		{			RelOptInfo *jrel;			jrel = make_join_rel(root, old_rel, other_rel, JOIN_INNER);			if (jrel)				result = lcons(jrel, result);		}	}	return result;}/* * make_rels_by_clauseless_joins *	  Given a relation 'old_rel' and a list of other relations *	  'other_rels', create a join relation between 'old_rel' and each *	  member of 'other_rels' that isn't already included in 'old_rel'. *	  The join rel nodes are returned in a list. * * 'old_rel' is the relation entry for the relation to be joined * 'other_rels': the first cell of a linked list containing the * other rels to be considered for joining * * Currently, this is only used with initial rels in other_rels, but it would * work for joining to joinrels too. */static List *make_rels_by_clauseless_joins(PlannerInfo *root,							  RelOptInfo *old_rel,							  ListCell *other_rels){

⌨️ 快捷键说明

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