initsplan.c

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

C
1,362
字号
/* * check_outerjoin_delay *		Detect whether a qual referencing the given relids must be delayed *		in application due to the presence of a lower outer join, and/or *		may force extra delay of higher-level outer joins. * * If the qual must be delayed, add relids to *relids_p to reflect the lowest * safe level for evaluating the qual, and return TRUE.  Any extra delay for * higher-level joins is reflected by setting delay_upper_joins to TRUE in * OuterJoinInfo structs. * * For an is_pushed_down qual, we can evaluate the qual as soon as (1) we have * all the rels it mentions, and (2) we are at or above any outer joins that * can null any of these rels and are below the syntactic location of the * given qual.	We must enforce (2) because pushing down such a clause below * the OJ might cause the OJ to emit null-extended rows that should not have * been formed, or that should have been rejected by the clause.  (This is * only an issue for non-strict quals, since if we can prove a qual mentioning * only nullable rels is strict, we'd have reduced the outer join to an inner * join in reduce_outer_joins().) * * To enforce (2), scan the oj_info_list and merge the required-relid sets of * any such OJs into the clause's own reference list.  At the time we are * called, the oj_info_list contains only outer joins below this qual.	We * have to repeat the scan until no new relids get added; this ensures that * the qual is suitably delayed regardless of the order in which OJs get * executed.  As an example, if we have one OJ with LHS=A, RHS=B, and one with * LHS=B, RHS=C, it is implied that these can be done in either order; if the * B/C join is done first then the join to A can null C, so a qual actually * mentioning only C cannot be applied below the join to A. * * For a non-pushed-down qual, this isn't going to determine where we place the * qual, but we need to determine outerjoin_delayed anyway for possible use * in reconsider_outer_join_clauses(). * * Lastly, a pushed-down qual that references the nullable side of any current * oj_info_list member and has to be evaluated above that OJ (because its * required relids overlap the LHS too) causes that OJ's delay_upper_joins * flag to be set TRUE.  This will prevent any higher-level OJs from * being interchanged with that OJ, which would result in not having any * correct place to evaluate the qual.	(The case we care about here is a * sub-select WHERE clause within the RHS of some outer join.  The WHERE * clause must effectively be treated as a degenerate clause of that outer * join's condition.  Rather than trying to match such clauses with joins * directly, we set delay_upper_joins here, and when the upper outer join * is processed by make_outerjoininfo, it will refrain from allowing the * two OJs to commute.) */static boolcheck_outerjoin_delay(PlannerInfo *root, Relids *relids_p,					  bool is_pushed_down){	Relids		relids = *relids_p;	bool		outerjoin_delayed;	bool		found_some;	outerjoin_delayed = false;	do	{		ListCell   *l;		found_some = false;		foreach(l, root->oj_info_list)		{			OuterJoinInfo *ojinfo = (OuterJoinInfo *) lfirst(l);			/* do we reference any nullable rels of this OJ? */			if (bms_overlap(relids, ojinfo->min_righthand) ||				(ojinfo->is_full_join &&				 bms_overlap(relids, ojinfo->min_lefthand)))			{				/* yes, so set the result flag */				outerjoin_delayed = true;				/* have we included all its rels in relids? */				if (!bms_is_subset(ojinfo->min_lefthand, relids) ||					!bms_is_subset(ojinfo->min_righthand, relids))				{					/* no, so add them in */					relids = bms_add_members(relids, ojinfo->min_lefthand);					relids = bms_add_members(relids, ojinfo->min_righthand);					/* we'll need another iteration */					found_some = true;				}				/* set delay_upper_joins if needed */				if (is_pushed_down && !ojinfo->is_full_join &&					bms_overlap(relids, ojinfo->min_lefthand))					ojinfo->delay_upper_joins = true;			}		}	} while (found_some);	*relids_p = relids;	return outerjoin_delayed;}/* * distribute_restrictinfo_to_rels *	  Push a completed RestrictInfo into the proper restriction or join *	  clause list(s). * * This is the last step of distribute_qual_to_rels() for ordinary qual * clauses.  Clauses that are interesting for equivalence-class processing * are diverted to the EC machinery, but may ultimately get fed back here. */voiddistribute_restrictinfo_to_rels(PlannerInfo *root,								RestrictInfo *restrictinfo){	Relids		relids = restrictinfo->required_relids;	RelOptInfo *rel;	switch (bms_membership(relids))	{		case BMS_SINGLETON:			/*			 * There is only one relation participating in the clause, so it			 * is a restriction clause for that relation.			 */			rel = find_base_rel(root, bms_singleton_member(relids));			/* Add clause to rel's restriction list */			rel->baserestrictinfo = lappend(rel->baserestrictinfo,											restrictinfo);			break;		case BMS_MULTIPLE:			/*			 * The clause is a join clause, since there is more than one rel			 * in its relid set.			 */			/*			 * Check for hashjoinable operators.  (We don't bother setting the			 * hashjoin info if we're not going to need it.)			 */			if (enable_hashjoin)				check_hashjoinable(restrictinfo);			/*			 * Add clause to the join lists of all the relevant relations.			 */			add_join_clause_to_rels(root, restrictinfo, relids);			break;		default:			/*			 * clause references no rels, and therefore we have no place to			 * attach it.  Shouldn't get here if callers are working properly.			 */			elog(ERROR, "cannot cope with variable-free clause");			break;	}}/* * process_implied_equality *	  Create a restrictinfo item that says "item1 op item2", and push it *	  into the appropriate lists.  (In practice opno is always a btree *	  equality operator.) * * "qualscope" is the nominal syntactic level to impute to the restrictinfo. * This must contain at least all the rels used in the expressions, but it * is used only to set the qual application level when both exprs are * variable-free.  Otherwise the qual is applied at the lowest join level * that provides all its variables. * * "both_const" indicates whether both items are known pseudo-constant; * in this case it is worth applying eval_const_expressions() in case we * can produce constant TRUE or constant FALSE.  (Otherwise it's not, * because the expressions went through eval_const_expressions already.) * * This is currently used only when an EquivalenceClass is found to * contain pseudoconstants.  See path/pathkeys.c for more details. */voidprocess_implied_equality(PlannerInfo *root,						 Oid opno,						 Expr *item1,						 Expr *item2,						 Relids qualscope,						 bool below_outer_join,						 bool both_const){	Expr	   *clause;	/*	 * Build the new clause.  Copy to ensure it shares no substructure with	 * original (this is necessary in case there are subselects in there...)	 */	clause = make_opclause(opno,						   BOOLOID,		/* opresulttype */						   false,		/* opretset */						   (Expr *) copyObject(item1),						   (Expr *) copyObject(item2));	/* If both constant, try to reduce to a boolean constant. */	if (both_const)	{		clause = (Expr *) eval_const_expressions(root, (Node *) clause);		/* If we produced const TRUE, just drop the clause */		if (clause && IsA(clause, Const))		{			Const	   *cclause = (Const *) clause;			Assert(cclause->consttype == BOOLOID);			if (!cclause->constisnull && DatumGetBool(cclause->constvalue))				return;		}	}	/* Make a copy of qualscope to avoid problems if source EC changes */	qualscope = bms_copy(qualscope);	/*	 * Push the new clause into all the appropriate restrictinfo lists.	 */	distribute_qual_to_rels(root, (Node *) clause,							true, below_outer_join,							qualscope, NULL, NULL);}/* * build_implied_join_equality --- build a RestrictInfo for a derived equality * * This overlaps the functionality of process_implied_equality(), but we * must return the RestrictInfo, not push it into the joininfo tree. */RestrictInfo *build_implied_join_equality(Oid opno,							Expr *item1,							Expr *item2,							Relids qualscope){	RestrictInfo *restrictinfo;	Expr	   *clause;	/*	 * Build the new clause.  Copy to ensure it shares no substructure with	 * original (this is necessary in case there are subselects in there...)	 */	clause = make_opclause(opno,						   BOOLOID,		/* opresulttype */						   false,		/* opretset */						   (Expr *) copyObject(item1),						   (Expr *) copyObject(item2));	/* Make a copy of qualscope to avoid problems if source EC changes */	qualscope = bms_copy(qualscope);	/*	 * Build the RestrictInfo node itself.	 */	restrictinfo = make_restrictinfo(clause,									 true,		/* is_pushed_down */									 false,		/* outerjoin_delayed */									 false,		/* pseudoconstant */									 qualscope);	/* Set mergejoinability info always, and hashjoinability if enabled */	check_mergejoinable(restrictinfo);	if (enable_hashjoin)		check_hashjoinable(restrictinfo);	return restrictinfo;}/***************************************************************************** * *	 CHECKS FOR MERGEJOINABLE AND HASHJOINABLE CLAUSES * *****************************************************************************//* * check_mergejoinable *	  If the restrictinfo's clause is mergejoinable, set the mergejoin *	  info fields in the restrictinfo. * *	  Currently, we support mergejoin for binary opclauses where *	  the operator is a mergejoinable operator.  The arguments can be *	  anything --- as long as there are no volatile functions in them. */static voidcheck_mergejoinable(RestrictInfo *restrictinfo){	Expr	   *clause = restrictinfo->clause;	Oid			opno;	if (restrictinfo->pseudoconstant)		return;	if (!is_opclause(clause))		return;	if (list_length(((OpExpr *) clause)->args) != 2)		return;	opno = ((OpExpr *) clause)->opno;	if (op_mergejoinable(opno) &&		!contain_volatile_functions((Node *) clause))		restrictinfo->mergeopfamilies = get_mergejoin_opfamilies(opno);	/*	 * Note: op_mergejoinable is just a hint; if we fail to find the operator	 * in any btree opfamilies, mergeopfamilies remains NIL and so the clause	 * is not treated as mergejoinable.	 */}/* * check_hashjoinable *	  If the restrictinfo's clause is hashjoinable, set the hashjoin *	  info fields in the restrictinfo. * *	  Currently, we support hashjoin for binary opclauses where *	  the operator is a hashjoinable operator.	The arguments can be *	  anything --- as long as there are no volatile functions in them. */static voidcheck_hashjoinable(RestrictInfo *restrictinfo){	Expr	   *clause = restrictinfo->clause;	Oid			opno;	if (restrictinfo->pseudoconstant)		return;	if (!is_opclause(clause))		return;	if (list_length(((OpExpr *) clause)->args) != 2)		return;	opno = ((OpExpr *) clause)->opno;	if (op_hashjoinable(opno) &&		!contain_volatile_functions((Node *) clause))		restrictinfo->hashjoinoperator = opno;}

⌨️ 快捷键说明

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