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

📄 prepjointree.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
				break;			default:				elog(ERROR, "unrecognized join type: %d",					 (int) j->jointype);				break;		}	}	else		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(jtnode));	return jtnode;}/* * is_simple_subquery *	  Check a subquery in the range table to see if it's simple enough *	  to pull up into the parent query. */static boolis_simple_subquery(Query *subquery){	/*	 * Let's just make sure it's a valid subselect ...	 */	if (!IsA(subquery, Query) ||		subquery->commandType != CMD_SELECT ||		subquery->resultRelation != 0 ||		subquery->into != NULL)		elog(ERROR, "subquery is bogus");	/*	 * Can't currently pull up a query with setops. Maybe after querytree	 * redesign...	 */	if (subquery->setOperations)		return false;	/*	 * Can't pull up a subquery involving grouping, aggregation, sorting, or	 * limiting.	 */	if (subquery->hasAggs ||		subquery->groupClause ||		subquery->havingQual ||		subquery->sortClause ||		subquery->distinctClause ||		subquery->limitOffset ||		subquery->limitCount)		return false;	/*	 * Don't pull up a subquery that has any set-returning functions in its	 * targetlist.	Otherwise we might well wind up inserting set-returning	 * functions into places where they mustn't go, such as quals of higher	 * queries.	 */	if (expression_returns_set((Node *) subquery->targetList))		return false;	/*	 * Hack: don't try to pull up a subquery with an empty jointree.	 * query_planner() will correctly generate a Result plan for a jointree	 * that's totally empty, but I don't think the right things happen if an	 * empty FromExpr appears lower down in a jointree. Not worth working hard	 * on this, just to collapse SubqueryScan/Result into Result...	 */	if (subquery->jointree->fromlist == NIL)		return false;	return true;}/* * has_nullable_targetlist *	  Check a subquery in the range table to see if all the non-junk *	  targetlist items are simple variables or strict functions of simple *	  variables (and, hence, will correctly go to NULL when examined above *	  the point of an outer join). * * NOTE: it would be correct (and useful) to ignore output columns that aren't * actually referenced by the enclosing query ... but we do not have that * information available at this point. */static boolhas_nullable_targetlist(Query *subquery){	ListCell   *l;	foreach(l, subquery->targetList)	{		TargetEntry *tle = (TargetEntry *) lfirst(l);		/* ignore resjunk columns */		if (tle->resjunk)			continue;		/* Must contain a Var of current level */		if (!contain_vars_of_level((Node *) tle->expr, 0))			return false;		/* Must not contain any non-strict constructs */		if (contain_nonstrict_functions((Node *) tle->expr))			return false;		/* This one's OK, keep scanning */	}	return true;}/* * Helper routine for pull_up_subqueries: do ResolveNew on every expression * in the jointree, without changing the jointree structure itself.  Ugly, * but there's no other way... */static voidresolvenew_in_jointree(Node *jtnode, int varno,					   RangeTblEntry *rte, List *subtlist){	if (jtnode == NULL)		return;	if (IsA(jtnode, RangeTblRef))	{		/* nothing to do here */	}	else if (IsA(jtnode, FromExpr))	{		FromExpr   *f = (FromExpr *) jtnode;		ListCell   *l;		foreach(l, f->fromlist)			resolvenew_in_jointree(lfirst(l), varno, rte, subtlist);		f->quals = ResolveNew(f->quals,							  varno, 0, rte,							  subtlist, CMD_SELECT, 0);	}	else if (IsA(jtnode, JoinExpr))	{		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, true);		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, true);				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;

⌨️ 快捷键说明

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