initsplan.c

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

C
1,362
字号
	ojinfo->min_righthand = min_righthand;	return ojinfo;}/***************************************************************************** * *	  QUALIFICATIONS * *****************************************************************************//* * distribute_qual_to_rels *	  Add clause information to either the baserestrictinfo or joininfo list *	  (depending on whether the clause is a join) of each base relation *	  mentioned in the clause.	A RestrictInfo node is created and added to *	  the appropriate list for each rel.  Alternatively, if the clause uses a *	  mergejoinable operator and is not delayed by outer-join rules, enter *	  the left- and right-side expressions into the query's list of *	  EquivalenceClasses. * * 'clause': the qual clause to be distributed * 'is_deduced': TRUE if the qual came from implied-equality deduction * 'below_outer_join': TRUE if the qual is from a JOIN/ON that is below the *		nullable side of a higher-level outer join * 'qualscope': set of baserels the qual's syntactic scope covers * 'ojscope': NULL if not an outer-join qual, else the minimum set of baserels *		needed to form this join * 'outerjoin_nonnullable': NULL if not an outer-join qual, else the set of *		baserels appearing on the outer (nonnullable) side of the join *		(for FULL JOIN this includes both sides of the join, and must in fact *		equal qualscope) * * 'qualscope' identifies what level of JOIN the qual came from syntactically. * 'ojscope' is needed if we decide to force the qual up to the outer-join * level, which will be ojscope not necessarily qualscope. */static voiddistribute_qual_to_rels(PlannerInfo *root, Node *clause,						bool is_deduced,						bool below_outer_join,						Relids qualscope,						Relids ojscope,						Relids outerjoin_nonnullable){	Relids		relids;	bool		is_pushed_down;	bool		outerjoin_delayed;	bool		pseudoconstant = false;	bool		maybe_equivalence;	bool		maybe_outer_join;	RestrictInfo *restrictinfo;	/*	 * Retrieve all relids mentioned within the clause.	 */	relids = pull_varnos(clause);	/*	 * Cross-check: clause should contain no relids not within its scope.	 * Otherwise the parser messed up.	 */	if (!bms_is_subset(relids, qualscope))		elog(ERROR, "JOIN qualification cannot refer to other relations");	if (ojscope && !bms_is_subset(relids, ojscope))		elog(ERROR, "JOIN qualification cannot refer to other relations");	/*	 * If the clause is variable-free, our normal heuristic for pushing it	 * down to just the mentioned rels doesn't work, because there are none.	 *	 * If the clause is an outer-join clause, we must force it to the OJ's	 * semantic level to preserve semantics.	 *	 * Otherwise, when the clause contains volatile functions, we force it to	 * be evaluated at its original syntactic level.  This preserves the	 * expected semantics.	 *	 * When the clause contains no volatile functions either, it is actually a	 * pseudoconstant clause that will not change value during any one	 * execution of the plan, and hence can be used as a one-time qual in a	 * gating Result plan node.  We put such a clause into the regular	 * RestrictInfo lists for the moment, but eventually createplan.c will	 * pull it out and make a gating Result node immediately above whatever	 * plan node the pseudoconstant clause is assigned to.	It's usually best	 * to put a gating node as high in the plan tree as possible. If we are	 * not below an outer join, we can actually push the pseudoconstant qual	 * all the way to the top of the tree.	If we are below an outer join, we	 * leave the qual at its original syntactic level (we could push it up to	 * just below the outer join, but that seems more complex than it's	 * worth).	 */	if (bms_is_empty(relids))	{		if (ojscope)		{			/* clause is attached to outer join, eval it there */			relids = bms_copy(ojscope);			/* mustn't use as gating qual, so don't mark pseudoconstant */		}		else		{			/* eval at original syntactic level */			relids = bms_copy(qualscope);			if (!contain_volatile_functions(clause))			{				/* mark as gating qual */				pseudoconstant = true;				/* tell createplan.c to check for gating quals */				root->hasPseudoConstantQuals = true;				/* if not below outer join, push it to top of tree */				if (!below_outer_join)					relids = get_relids_in_jointree((Node *) root->parse->jointree);			}		}	}	/*----------	 * Check to see if clause application must be delayed by outer-join	 * considerations.	 *	 * A word about is_pushed_down: we mark the qual as "pushed down" if	 * it is (potentially) applicable at a level different from its original	 * syntactic level.  This flag is used to distinguish OUTER JOIN ON quals	 * from other quals pushed down to the same joinrel.  The rules are:	 *		WHERE quals and INNER JOIN quals: is_pushed_down = true.	 *		Non-degenerate OUTER JOIN quals: is_pushed_down = false.	 *		Degenerate OUTER JOIN quals: is_pushed_down = true.	 * A "degenerate" OUTER JOIN qual is one that doesn't mention the	 * non-nullable side, and hence can be pushed down into the nullable side	 * without changing the join result.  It is correct to treat it as a	 * regular filter condition at the level where it is evaluated.	 *	 * Note: it is not immediately obvious that a simple boolean is enough	 * for this: if for some reason we were to attach a degenerate qual to	 * its original join level, it would need to be treated as an outer join	 * qual there.	However, this cannot happen, because all the rels the	 * clause mentions must be in the outer join's min_righthand, therefore	 * the join it needs must be formed before the outer join; and we always	 * attach quals to the lowest level where they can be evaluated.  But	 * if we were ever to re-introduce a mechanism for delaying evaluation	 * of "expensive" quals, this area would need work.	 *----------	 */	if (is_deduced)	{		/*		 * If the qual came from implied-equality deduction, it should not be		 * outerjoin-delayed, else deducer blew it.  But we can't check this		 * because the ojinfo list may now contain OJs above where the qual		 * belongs.		 */		Assert(!ojscope);		is_pushed_down = true;		outerjoin_delayed = false;		/* Don't feed it back for more deductions */		maybe_equivalence = false;		maybe_outer_join = false;	}	else if (bms_overlap(relids, outerjoin_nonnullable))	{		/*		 * The qual is attached to an outer join and mentions (some of the)		 * rels on the nonnullable side, so it's not degenerate.		 *		 * We can't use such a clause to deduce equivalence (the left and		 * right sides might be unequal above the join because one of them has		 * gone to NULL) ... but we might be able to use it for more limited		 * deductions, if it is mergejoinable.  So consider adding it to the		 * lists of set-aside outer-join clauses.		 */		is_pushed_down = false;		maybe_equivalence = false;		maybe_outer_join = true;		/* Check to see if must be delayed by lower outer join */		outerjoin_delayed = check_outerjoin_delay(root, &relids, false);		/*		 * Now force the qual to be evaluated exactly at the level of joining		 * corresponding to the outer join.  We cannot let it get pushed down		 * into the nonnullable side, since then we'd produce no output rows,		 * rather than the intended single null-extended row, for any		 * nonnullable-side rows failing the qual.		 *		 * (Do this step after calling check_outerjoin_delay, because that		 * trashes relids.)		 */		Assert(ojscope);		relids = ojscope;		Assert(!pseudoconstant);	}	else	{		/*		 * Normal qual clause or degenerate outer-join clause.	Either way, we		 * can mark it as pushed-down.		 */		is_pushed_down = true;		/* Check to see if must be delayed by lower outer join */		outerjoin_delayed = check_outerjoin_delay(root, &relids, true);		if (outerjoin_delayed)		{			/* Should still be a subset of current scope ... */			Assert(bms_is_subset(relids, qualscope));			/*			 * Because application of the qual will be delayed by outer join,			 * we mustn't assume its vars are equal everywhere.			 */			maybe_equivalence = false;		}		else		{			/*			 * Qual is not delayed by any lower outer-join restriction, so we			 * can consider feeding it to the equivalence machinery. However,			 * if it's itself within an outer-join clause, treat it as though			 * it appeared below that outer join (note that we can only get			 * here when the clause references only nullable-side rels).			 */			maybe_equivalence = true;			if (outerjoin_nonnullable != NULL)				below_outer_join = true;		}		/*		 * Since it doesn't mention the LHS, it's certainly not useful as a		 * set-aside OJ clause, even if it's in an OJ.		 */		maybe_outer_join = false;	}	/*	 * Build the RestrictInfo node itself.	 */	restrictinfo = make_restrictinfo((Expr *) clause,									 is_pushed_down,									 outerjoin_delayed,									 pseudoconstant,									 relids);	/*	 * If it's a join clause (either naturally, or because delayed by	 * outer-join rules), add vars used in the clause to targetlists of their	 * relations, so that they will be emitted by the plan nodes that scan	 * those relations (else they won't be available at the join node!).	 *	 * Note: if the clause gets absorbed into an EquivalenceClass then this	 * may be unnecessary, but for now we have to do it to cover the case	 * where the EC becomes ec_broken and we end up reinserting the original	 * clauses into the plan.	 */	if (bms_membership(relids) == BMS_MULTIPLE)	{		List	   *vars = pull_var_clause(clause, false);		add_vars_to_targetlist(root, vars, relids);		list_free(vars);	}	/*	 * We check "mergejoinability" of every clause, not only join clauses,	 * because we want to know about equivalences between vars of the same	 * relation, or between vars and consts.	 */	check_mergejoinable(restrictinfo);	/*	 * If it is a true equivalence clause, send it to the EquivalenceClass	 * machinery.  We do *not* attach it directly to any restriction or join	 * lists.  The EC code will propagate it to the appropriate places later.	 *	 * If the clause has a mergejoinable operator and is not	 * outerjoin-delayed, yet isn't an equivalence because it is an outer-join	 * clause, the EC code may yet be able to do something with it.  We add it	 * to appropriate lists for further consideration later.  Specifically:	 *	 * If it is a left or right outer-join qualification that relates the two	 * sides of the outer join (no funny business like leftvar1 = leftvar2 +	 * rightvar), we add it to root->left_join_clauses or	 * root->right_join_clauses according to which side the nonnullable	 * variable appears on.	 *	 * If it is a full outer-join qualification, we add it to	 * root->full_join_clauses.  (Ideally we'd discard cases that aren't	 * leftvar = rightvar, as we do for left/right joins, but this routine	 * doesn't have the info needed to do that; and the current usage of the	 * full_join_clauses list doesn't require that, so it's not currently	 * worth complicating this routine's API to make it possible.)	 *	 * If none of the above hold, pass it off to	 * distribute_restrictinfo_to_rels().	 */	if (restrictinfo->mergeopfamilies)	{		if (maybe_equivalence)		{			if (process_equivalence(root, restrictinfo, below_outer_join))				return;			/* EC rejected it, so pass to distribute_restrictinfo_to_rels */		}		else if (maybe_outer_join && restrictinfo->can_join)		{			if (bms_is_subset(restrictinfo->left_relids,							  outerjoin_nonnullable) &&				!bms_overlap(restrictinfo->right_relids,							 outerjoin_nonnullable))			{				/* we have outervar = innervar */				root->left_join_clauses = lappend(root->left_join_clauses,												  restrictinfo);				return;			}			if (bms_is_subset(restrictinfo->right_relids,							  outerjoin_nonnullable) &&				!bms_overlap(restrictinfo->left_relids,							 outerjoin_nonnullable))			{				/* we have innervar = outervar */				root->right_join_clauses = lappend(root->right_join_clauses,												   restrictinfo);				return;			}			if (bms_equal(outerjoin_nonnullable, qualscope))			{				/* FULL JOIN (above tests cannot match in this case) */				root->full_join_clauses = lappend(root->full_join_clauses,												  restrictinfo);				return;			}		}	}	/* No EC special case applies, so push it into the clause lists */	distribute_restrictinfo_to_rels(root, restrictinfo);}

⌨️ 快捷键说明

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