joinrels.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 629 行 · 第 1/2 页

C
629
字号
	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': 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(Query *root,							  RelOptInfo *old_rel,							  List *other_rels){	List	   *result = NIL;	List	   *i;	foreach(i, other_rels)	{		RelOptInfo *other_rel = (RelOptInfo *) lfirst(i);		if (!bms_overlap(other_rel->relids, old_rel->relids))		{			RelOptInfo *jrel;			jrel = make_join_rel(root, old_rel, other_rel, JOIN_INNER);			/*			 * As long as given other_rels are distinct, don't need to			 * test to see if jrel is already part of output list.			 */			if (jrel)				result = lcons(jrel, result);		}	}	return result;}/* * is_inside_IN *		Detect whether the specified relation is inside an IN (sub-SELECT). * * Note that we are actually only interested in rels that have been pulled up * out of an IN, so the routine name is a slight misnomer. */static boolis_inside_IN(Query *root, RelOptInfo *rel){	List	   *i;	foreach(i, root->in_info_list)	{		InClauseInfo *ininfo = (InClauseInfo *) lfirst(i);		if (bms_is_subset(rel->relids, ininfo->righthand))			return true;	}	return false;}/* * make_jointree_rel *		Find or build a RelOptInfo join rel representing a specific *		jointree item.	For JoinExprs, we only consider the construction *		path that corresponds exactly to what the user wrote. */RelOptInfo *make_jointree_rel(Query *root, Node *jtnode){	if (IsA(jtnode, RangeTblRef))	{		int			varno = ((RangeTblRef *) jtnode)->rtindex;		return find_base_rel(root, varno);	}	else if (IsA(jtnode, FromExpr))	{		FromExpr   *f = (FromExpr *) jtnode;		/* Recurse back to multi-way-join planner */		return make_fromexpr_rel(root, f);	}	else if (IsA(jtnode, JoinExpr))	{		JoinExpr   *j = (JoinExpr *) jtnode;		RelOptInfo *rel,				   *lrel,				   *rrel;		/* Recurse */		lrel = make_jointree_rel(root, j->larg);		rrel = make_jointree_rel(root, j->rarg);		/* Make this join rel */		rel = make_join_rel(root, lrel, rrel, j->jointype);		if (rel == NULL)		/* oops */			elog(ERROR, "invalid join order");		/*		 * Since we are only going to consider this one way to do it,		 * we're done generating Paths for this joinrel and can now select		 * the cheapest.  In fact we *must* do so now, since next level up		 * will need it!		 */		set_cheapest(rel);#ifdef OPTIMIZER_DEBUG		debug_print_rel(root, rel);#endif		return rel;	}	else		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(jtnode));	return NULL;				/* keep compiler quiet */}/* * make_join_rel *	   Find or create a join RelOptInfo that represents the join of *	   the two given rels, and add to it path information for paths *	   created with the two rels as outer and inner rel. *	   (The join rel may already contain paths generated from other *	   pairs of rels that add up to the same set of base rels.) * * NB: will return NULL if attempted join is not valid.  This can only * happen when working with IN clauses that have been turned into joins. */RelOptInfo *make_join_rel(Query *root, RelOptInfo *rel1, RelOptInfo *rel2,			  JoinType jointype){	Relids		joinrelids;	RelOptInfo *joinrel;	List	   *restrictlist;	/* We should never try to join two overlapping sets of rels. */	Assert(!bms_overlap(rel1->relids, rel2->relids));	/* Construct Relids set that identifies the joinrel. */	joinrelids = bms_union(rel1->relids, rel2->relids);	/*	 * If we are implementing IN clauses as joins, there are some joins	 * that are illegal.  Check to see if the proposed join is trouble. We	 * can skip the work if looking at an outer join, however, because	 * only top-level joins might be affected.	 */	if (jointype == JOIN_INNER)	{		List	   *l;		foreach(l, root->in_info_list)		{			InClauseInfo *ininfo = (InClauseInfo *) lfirst(l);			/*			 * Cannot join if proposed join contains part, but only part,			 * of the RHS, *and* it contains rels not in the RHS.			 */			if (bms_overlap(ininfo->righthand, joinrelids) &&				!bms_is_subset(ininfo->righthand, joinrelids) &&				!bms_is_subset(joinrelids, ininfo->righthand))			{				bms_free(joinrelids);				return NULL;			}			/*			 * No issue unless we are looking at a join of the IN's RHS to			 * other stuff.			 */			if (!(bms_is_subset(ininfo->righthand, joinrelids) &&				  !bms_equal(ininfo->righthand, joinrelids)))				continue;			/*			 * If we already joined IN's RHS to any part of its LHS in			 * either input path, then this join is not constrained (the			 * necessary work was done at a lower level).			 */			if (bms_overlap(ininfo->lefthand, rel1->relids) &&				bms_is_subset(ininfo->righthand, rel1->relids))				continue;			if (bms_overlap(ininfo->lefthand, rel2->relids) &&				bms_is_subset(ininfo->righthand, rel2->relids))				continue;			/*			 * JOIN_IN technique will work if outerrel includes LHS and			 * innerrel is exactly RHS; conversely JOIN_REVERSE_IN handles			 * RHS/LHS.			 *			 * JOIN_UNIQUE_OUTER will work if outerrel is exactly RHS;			 * conversely JOIN_UNIQUE_INNER will work if innerrel is			 * exactly RHS.			 *			 * But none of these will work if we already found another IN			 * that needs to trigger here.			 */			if (jointype != JOIN_INNER)			{				bms_free(joinrelids);				return NULL;			}			if (bms_is_subset(ininfo->lefthand, rel1->relids) &&				bms_equal(ininfo->righthand, rel2->relids))				jointype = JOIN_IN;			else if (bms_is_subset(ininfo->lefthand, rel2->relids) &&					 bms_equal(ininfo->righthand, rel1->relids))				jointype = JOIN_REVERSE_IN;			else if (bms_equal(ininfo->righthand, rel1->relids))				jointype = JOIN_UNIQUE_OUTER;			else if (bms_equal(ininfo->righthand, rel2->relids))				jointype = JOIN_UNIQUE_INNER;			else			{				/* invalid join path */				bms_free(joinrelids);				return NULL;			}		}	}	/*	 * Find or build the join RelOptInfo, and compute the restrictlist	 * that goes with this particular joining.	 */	joinrel = build_join_rel(root, joinrelids, rel1, rel2, jointype,							 &restrictlist);	/*	 * Consider paths using each rel as both outer and inner.	 */	switch (jointype)	{		case JOIN_INNER:			add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_INNER,								 restrictlist);			add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_INNER,								 restrictlist);			break;		case JOIN_LEFT:			add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_LEFT,								 restrictlist);			add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_RIGHT,								 restrictlist);			break;		case JOIN_FULL:			add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_FULL,								 restrictlist);			add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_FULL,								 restrictlist);			break;		case JOIN_RIGHT:			add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_RIGHT,								 restrictlist);			add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_LEFT,								 restrictlist);			break;		case JOIN_IN:			add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_IN,								 restrictlist);			/* REVERSE_IN isn't supported by joinpath.c */			add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_UNIQUE_INNER,								 restrictlist);			add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_UNIQUE_OUTER,								 restrictlist);			break;		case JOIN_REVERSE_IN:			/* REVERSE_IN isn't supported by joinpath.c */			add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_IN,								 restrictlist);			add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_UNIQUE_OUTER,								 restrictlist);			add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_UNIQUE_INNER,								 restrictlist);			break;		case JOIN_UNIQUE_OUTER:			add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_UNIQUE_OUTER,								 restrictlist);			add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_UNIQUE_INNER,								 restrictlist);			break;		case JOIN_UNIQUE_INNER:			add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_UNIQUE_INNER,								 restrictlist);			add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_UNIQUE_OUTER,								 restrictlist);			break;		default:			elog(ERROR, "unrecognized join type: %d",				 (int) jointype);			break;	}	bms_free(joinrelids);	return joinrel;}

⌨️ 快捷键说明

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