prepjointree.c

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

C
1,329
字号
		JoinExpr   *j = (JoinExpr *) jtnode;		resolvenew_in_jointree(j->larg, varno, rte, subtlist);		resolvenew_in_jointree(j->rarg, varno, rte, subtlist);		j->quals = ResolveNew(j->quals,							  varno, 0, rte,							  subtlist, CMD_SELECT, 0);		/*		 * We don't bother to update the colvars list, since it won't be used		 * again ...		 */	}	else		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(jtnode));}/* * reduce_outer_joins *		Attempt to reduce outer joins to plain inner joins. * * The idea here is that given a query like *		SELECT ... FROM a LEFT JOIN b ON (...) WHERE b.y = 42; * we can reduce the LEFT JOIN to a plain JOIN if the "=" operator in WHERE * is strict.  The strict operator will always return NULL, causing the outer * WHERE to fail, on any row where the LEFT JOIN filled in NULLs for b's * columns.  Therefore, there's no need for the join to produce null-extended * rows in the first place --- which makes it a plain join not an outer join. * (This scenario may not be very likely in a query written out by hand, but * it's reasonably likely when pushing quals down into complex views.) * * More generally, an outer join can be reduced in strength if there is a * strict qual above it in the qual tree that constrains a Var from the * nullable side of the join to be non-null.  (For FULL joins this applies * to each side separately.) * * To ease recognition of strict qual clauses, we require this routine to be * run after expression preprocessing (i.e., qual canonicalization and JOIN * alias-var expansion). */voidreduce_outer_joins(PlannerInfo *root){	reduce_outer_joins_state *state;	/*	 * To avoid doing strictness checks on more quals than necessary, we want	 * to stop descending the jointree as soon as there are no outer joins	 * below our current point.  This consideration forces a two-pass process.	 * The first pass gathers information about which base rels appear below	 * each side of each join clause, and about whether there are outer	 * join(s) below each side of each join clause. The second pass examines	 * qual clauses and changes join types as it descends the tree.	 */	state = reduce_outer_joins_pass1((Node *) root->parse->jointree);	/* planner.c shouldn't have called me if no outer joins */	if (state == NULL || !state->contains_outer)		elog(ERROR, "so where are the outer joins?");	reduce_outer_joins_pass2((Node *) root->parse->jointree,							 state, root, NULL);}/* * reduce_outer_joins_pass1 - phase 1 data collection * * Returns a state node describing the given jointree node. */static reduce_outer_joins_state *reduce_outer_joins_pass1(Node *jtnode){	reduce_outer_joins_state *result;	result = (reduce_outer_joins_state *)		palloc(sizeof(reduce_outer_joins_state));	result->relids = NULL;	result->contains_outer = false;	result->sub_states = NIL;	if (jtnode == NULL)		return result;	if (IsA(jtnode, RangeTblRef))	{		int			varno = ((RangeTblRef *) jtnode)->rtindex;		result->relids = bms_make_singleton(varno);	}	else if (IsA(jtnode, FromExpr))	{		FromExpr   *f = (FromExpr *) jtnode;		ListCell   *l;		foreach(l, f->fromlist)		{			reduce_outer_joins_state *sub_state;			sub_state = reduce_outer_joins_pass1(lfirst(l));			result->relids = bms_add_members(result->relids,											 sub_state->relids);			result->contains_outer |= sub_state->contains_outer;			result->sub_states = lappend(result->sub_states, sub_state);		}	}	else if (IsA(jtnode, JoinExpr))	{		JoinExpr   *j = (JoinExpr *) jtnode;		reduce_outer_joins_state *sub_state;		/* join's own RT index is not wanted in result->relids */		if (IS_OUTER_JOIN(j->jointype))			result->contains_outer = true;		sub_state = reduce_outer_joins_pass1(j->larg);		result->relids = bms_add_members(result->relids,										 sub_state->relids);		result->contains_outer |= sub_state->contains_outer;		result->sub_states = lappend(result->sub_states, sub_state);		sub_state = reduce_outer_joins_pass1(j->rarg);		result->relids = bms_add_members(result->relids,										 sub_state->relids);		result->contains_outer |= sub_state->contains_outer;		result->sub_states = lappend(result->sub_states, sub_state);	}	else		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(jtnode));	return result;}/* * reduce_outer_joins_pass2 - phase 2 processing * *	jtnode: current jointree node *	state: state data collected by phase 1 for this node *	root: toplevel planner state *	nonnullable_rels: set of base relids forced non-null by upper quals */static voidreduce_outer_joins_pass2(Node *jtnode,						 reduce_outer_joins_state *state,						 PlannerInfo *root,						 Relids nonnullable_rels){	/*	 * pass 2 should never descend as far as an empty subnode or base rel,	 * because it's only called on subtrees marked as contains_outer.	 */	if (jtnode == NULL)		elog(ERROR, "reached empty jointree");	if (IsA(jtnode, RangeTblRef))		elog(ERROR, "reached base rel");	else if (IsA(jtnode, FromExpr))	{		FromExpr   *f = (FromExpr *) jtnode;		ListCell   *l;		ListCell   *s;		Relids		pass_nonnullable;		/* Scan quals to see if we can add any nonnullability constraints */		pass_nonnullable = find_nonnullable_rels(f->quals);		pass_nonnullable = bms_add_members(pass_nonnullable,										   nonnullable_rels);		/* And recurse --- but only into interesting subtrees */		Assert(list_length(f->fromlist) == list_length(state->sub_states));		forboth(l, f->fromlist, s, state->sub_states)		{			reduce_outer_joins_state *sub_state = lfirst(s);			if (sub_state->contains_outer)				reduce_outer_joins_pass2(lfirst(l), sub_state, root,										 pass_nonnullable);		}		bms_free(pass_nonnullable);	}	else if (IsA(jtnode, JoinExpr))	{		JoinExpr   *j = (JoinExpr *) jtnode;		int			rtindex = j->rtindex;		JoinType	jointype = j->jointype;		reduce_outer_joins_state *left_state = linitial(state->sub_states);		reduce_outer_joins_state *right_state = lsecond(state->sub_states);		/* Can we simplify this join? */		switch (jointype)		{			case JOIN_LEFT:				if (bms_overlap(nonnullable_rels, right_state->relids))					jointype = JOIN_INNER;				break;			case JOIN_RIGHT:				if (bms_overlap(nonnullable_rels, left_state->relids))					jointype = JOIN_INNER;				break;			case JOIN_FULL:				if (bms_overlap(nonnullable_rels, left_state->relids))				{					if (bms_overlap(nonnullable_rels, right_state->relids))						jointype = JOIN_INNER;					else						jointype = JOIN_LEFT;				}				else				{					if (bms_overlap(nonnullable_rels, right_state->relids))						jointype = JOIN_RIGHT;				}				break;			default:				break;		}		if (jointype != j->jointype)		{			/* apply the change to both jointree node and RTE */			RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable);			Assert(rte->rtekind == RTE_JOIN);			Assert(rte->jointype == j->jointype);			rte->jointype = j->jointype = jointype;		}		/* Only recurse if there's more to do below here */		if (left_state->contains_outer || right_state->contains_outer)		{			Relids		local_nonnullable;			Relids		pass_nonnullable;			/*			 * If this join is (now) inner, we can add any nonnullability			 * constraints its quals provide to those we got from above. But			 * if it is outer, we can only pass down the local constraints			 * into the nullable side, because an outer join never eliminates			 * any rows from its non-nullable side.  If it's a FULL join then			 * it doesn't eliminate anything from either side.			 */			if (jointype != JOIN_FULL)			{				local_nonnullable = find_nonnullable_rels(j->quals);				local_nonnullable = bms_add_members(local_nonnullable,													nonnullable_rels);			}			else				local_nonnullable = NULL;		/* no use in calculating it */			if (left_state->contains_outer)			{				if (jointype == JOIN_INNER || jointype == JOIN_RIGHT)					pass_nonnullable = local_nonnullable;				else					pass_nonnullable = nonnullable_rels;				reduce_outer_joins_pass2(j->larg, left_state, root,										 pass_nonnullable);			}			if (right_state->contains_outer)			{				if (jointype == JOIN_INNER || jointype == JOIN_LEFT)					pass_nonnullable = local_nonnullable;				else					pass_nonnullable = nonnullable_rels;				reduce_outer_joins_pass2(j->rarg, right_state, root,										 pass_nonnullable);			}			bms_free(local_nonnullable);		}	}	else		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(jtnode));}/* * fix_in_clause_relids: update RT-index sets of InClauseInfo nodes * * When we pull up a subquery, any InClauseInfo references to the subquery's * RT index have to be replaced by the set of substituted relids. * * We assume we may modify the InClauseInfo nodes in-place. */static voidfix_in_clause_relids(List *in_info_list, int varno, Relids subrelids){	ListCell   *l;	foreach(l, in_info_list)	{		InClauseInfo *ininfo = (InClauseInfo *) lfirst(l);		if (bms_is_member(varno, ininfo->lefthand))		{			ininfo->lefthand = bms_del_member(ininfo->lefthand, varno);			ininfo->lefthand = bms_add_members(ininfo->lefthand, subrelids);		}		if (bms_is_member(varno, ininfo->righthand))		{			ininfo->righthand = bms_del_member(ininfo->righthand, varno);			ininfo->righthand = bms_add_members(ininfo->righthand, subrelids);		}	}}/* * fix_append_rel_relids: update RT-index fields of AppendRelInfo nodes * * When we pull up a subquery, any AppendRelInfo references to the subquery's * RT index have to be replaced by the substituted relid (and there had better * be only one). * * We assume we may modify the AppendRelInfo nodes in-place. */static voidfix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids){	ListCell   *l;	int			subvarno = -1;	/*	 * We only want to extract the member relid once, but we mustn't fail	 * immediately if there are multiple members; it could be that none of the	 * AppendRelInfo nodes refer to it.  So compute it on first use. Note that	 * bms_singleton_member will complain if set is not singleton.	 */	foreach(l, append_rel_list)	{		AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);		/* The parent_relid shouldn't ever be a pullup target */		Assert(appinfo->parent_relid != varno);		if (appinfo->child_relid == varno)		{			if (subvarno < 0)				subvarno = bms_singleton_member(subrelids);			appinfo->child_relid = subvarno;		}	}}/* * get_relids_in_jointree: get set of base RT indexes present in a jointree */Relidsget_relids_in_jointree(Node *jtnode){	Relids		result = NULL;	if (jtnode == NULL)		return result;	if (IsA(jtnode, RangeTblRef))	{		int			varno = ((RangeTblRef *) jtnode)->rtindex;		result = bms_make_singleton(varno);	}	else if (IsA(jtnode, FromExpr))	{		FromExpr   *f = (FromExpr *) jtnode;		ListCell   *l;		foreach(l, f->fromlist)		{			result = bms_join(result,							  get_relids_in_jointree(lfirst(l)));		}	}	else if (IsA(jtnode, JoinExpr))	{		JoinExpr   *j = (JoinExpr *) jtnode;		/* join's own RT index is not wanted in result */		result = get_relids_in_jointree(j->larg);		result = bms_join(result, get_relids_in_jointree(j->rarg));	}	else		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(jtnode));	return result;}/* * get_relids_for_join: get set of base RT indexes making up a join */Relidsget_relids_for_join(PlannerInfo *root, int joinrelid){	Node	   *jtnode;	jtnode = find_jointree_node_for_rel((Node *) root->parse->jointree,										joinrelid);	if (!jtnode)		elog(ERROR, "could not find join node %d", joinrelid);	return get_relids_in_jointree(jtnode);}/* * find_jointree_node_for_rel: locate jointree node for a base or join RT index * * Returns NULL if not found */static Node *find_jointree_node_for_rel(Node *jtnode, int relid){	if (jtnode == NULL)		return NULL;	if (IsA(jtnode, RangeTblRef))	{		int			varno = ((RangeTblRef *) jtnode)->rtindex;		if (relid == varno)			return jtnode;	}	else if (IsA(jtnode, FromExpr))	{		FromExpr   *f = (FromExpr *) jtnode;		ListCell   *l;		foreach(l, f->fromlist)		{			jtnode = find_jointree_node_for_rel(lfirst(l), relid);			if (jtnode)				return jtnode;		}	}	else if (IsA(jtnode, JoinExpr))	{		JoinExpr   *j = (JoinExpr *) jtnode;		if (relid == j->rtindex)			return jtnode;		jtnode = find_jointree_node_for_rel(j->larg, relid);		if (jtnode)			return jtnode;		jtnode = find_jointree_node_for_rel(j->rarg, relid);		if (jtnode)			return jtnode;	}	else		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(jtnode));	return NULL;}

⌨️ 快捷键说明

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