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

📄 initsplan.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
		/*		 * Since we do this bottom-up, any outer-rels previously marked should		 * be within the new outer join set.		 */		Assert(bms_is_subset(rel->outerjoinset, outerrels));		/*		 * Presently the executor cannot support FOR UPDATE/SHARE marking of		 * rels appearing on the nullable side of an outer join. (It's		 * somewhat unclear what that would mean, anyway: what should we mark		 * when a result row is generated from no element of the nullable		 * relation?)  So, complain if target rel is FOR UPDATE/SHARE. It's		 * sufficient to make this check once per rel, so do it only if rel		 * wasn't already known nullable.		 */		if (rel->outerjoinset == NULL)		{			if (list_member_int(root->parse->rowMarks, relno))				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("SELECT FOR UPDATE/SHARE cannot be applied to the nullable side of an outer join")));		}		rel->outerjoinset = outerrels;	}	bms_free(tmprelids);}/* * 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.  Also, 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 lists of *	  equijoined vars. * * 'clause': the qual clause to be distributed * 'is_pushed_down': if TRUE, force the clause to be marked 'is_pushed_down' *		(this indicates the clause came from a FromExpr, not a JoinExpr) * '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. * 'outerjoin_nonnullable': NULL if not an outer-join qual, else the set of *		baserels appearing on the outer (nonnullable) side of the join * 'qualscope': set of baserels the qual's syntactic scope covers * * 'qualscope' identifies what level of JOIN the qual came from.  For a top * level qual (WHERE qual), qualscope lists all baserel ids and in addition * 'is_pushed_down' will be TRUE. */static voiddistribute_qual_to_rels(PlannerInfo *root, Node *clause,						bool is_pushed_down,						bool is_deduced,						bool below_outer_join,						Relids outerjoin_nonnullable,						Relids qualscope){	Relids		relids;	bool		outerjoin_delayed;	bool		maybe_equijoin;	bool		maybe_outer_join;	RestrictInfo *restrictinfo;	RelOptInfo *rel;	List	   *vars;	/*	 * 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 may not refer to other relations");	/*	 * If the clause is variable-free, we force it to be evaluated at its	 * original syntactic level.  Note that this should not happen for	 * top-level clauses, because query_planner() special-cases them.  But it	 * will happen for variable-free JOIN/ON clauses.  We don't have to be	 * real smart about such a case, we just have to be correct.	 */	if (bms_is_empty(relids))		relids = qualscope;	/*	 * Check to see if clause application must be delayed by outer-join	 * considerations.	 */	if (is_deduced)	{		/*		 * If the qual came from implied-equality deduction, we always		 * evaluate the qual at its natural semantic level.  It is the		 * responsibility of the deducer not to create any quals that should		 * be delayed by outer-join rules.		 */		Assert(bms_equal(relids, qualscope));		/* Needn't feed it back for more deductions */		outerjoin_delayed = false;		maybe_equijoin = 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.  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.		 *		 * Note: an outer-join qual that mentions only nullable-side rels can		 * be pushed down into the nullable side without changing the join		 * result, so we treat it the same as an ordinary inner-join qual,		 * except for not setting maybe_equijoin (see below).		 */		relids = qualscope;		outerjoin_delayed = true;		/*		 * We can't use such a clause to deduce equijoin (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		 * purposes.  Note: for the current uses of deductions from an		 * outer-join clause, it seems safe to make the deductions even when		 * the clause is below a higher-level outer join; so we do not check		 * below_outer_join here.		 */		maybe_equijoin = false;		maybe_outer_join = true;	}	else	{		/*		 * For a non-outer-join 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. To enforce the latter, scan		 * the base rels listed in relids, and merge their outer-join sets		 * into the clause's own reference list.  At the time we are called,		 * the outerjoinset of each baserel will show exactly those outer		 * joins that are below the qual in the join tree.		 */		Relids		addrelids = NULL;		Relids		tmprelids;		int			relno;		outerjoin_delayed = false;		tmprelids = bms_copy(relids);		while ((relno = bms_first_member(tmprelids)) >= 0)		{			RelOptInfo *rel = find_base_rel(root, relno);			if (rel->outerjoinset != NULL)			{				addrelids = bms_add_members(addrelids, rel->outerjoinset);				outerjoin_delayed = true;			}		}		bms_free(tmprelids);		if (bms_is_subset(addrelids, relids))		{			/*			 * Qual is not delayed by any lower outer-join restriction. If it			 * is not itself below or within an outer join, we can consider it			 * "valid everywhere", so consider feeding it to the equijoin			 * machinery.  (If it is within an outer join, we can't consider			 * it "valid everywhere": once the contained variables have gone			 * to NULL, we'd be asserting things like NULL = NULL, which is			 * not true.)			 */			if (!below_outer_join && outerjoin_nonnullable == NULL)				maybe_equijoin = true;			else				maybe_equijoin = false;		}		else		{			relids = bms_union(relids, addrelids);			/* 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_equijoin = false;		}		bms_free(addrelids);		maybe_outer_join = false;	}	/*	 * Mark the qual as "pushed down" if it can be applied at a level below	 * its original syntactic level.  This allows us to distinguish original	 * JOIN/ON quals from higher-level quals pushed down to the same joinrel.	 * A qual originating from WHERE is always considered "pushed down".	 */	if (!is_pushed_down)		is_pushed_down = !bms_equal(relids, qualscope);	/*	 * Build the RestrictInfo node itself.	 */	restrictinfo = make_restrictinfo((Expr *) clause,									 is_pushed_down,									 outerjoin_delayed,									 relids);	/*	 * Figure out where to attach it.	 */	switch (bms_membership(relids))	{		case BMS_SINGLETON:			/*			 * There is only one relation participating in 'clause', so			 * 'clause' is a restriction clause for that relation.			 */			rel = find_base_rel(root, bms_singleton_member(relids));			/*			 * Check for a "mergejoinable" clause even though it's not a join			 * clause.	This is so that we can recognize that "a.x = a.y"			 * makes x and y eligible to be considered equal, even when they			 * belong to the same rel.	Without this, we would not recognize			 * that "a.x = a.y AND a.x = b.z AND a.y = c.q" allows us to			 * consider z and q equal after their rels are joined.			 */			check_mergejoinable(restrictinfo);			/*			 * If the clause was deduced from implied equality, check to see			 * whether it is redundant with restriction clauses we already			 * have for this rel.  Note we cannot apply this check to			 * user-written clauses, since we haven't found the canonical			 * pathkey sets yet while processing user clauses. (NB: no			 * comparable check is done in the join-clause case; redundancy			 * will be detected when the join clause is moved into a join			 * rel's restriction list.)			 */			if (!is_deduced ||				!qual_is_redundant(root, restrictinfo,								   rel->baserestrictinfo))			{				/* Add clause to rel's restriction list */				rel->baserestrictinfo = lappend(rel->baserestrictinfo,												restrictinfo);			}			break;		case BMS_MULTIPLE:			/*			 * 'clause' is a join clause, since there is more than one rel in			 * the relid set.			 */			/*			 * Check for hash or mergejoinable operators.			 *			 * We don't bother setting the hashjoin info if we're not going to			 * need it.  We do want to know about mergejoinable ops in all			 * cases, however, because we use mergejoinable ops for other			 * purposes such as detecting redundant clauses.			 */			check_mergejoinable(restrictinfo);			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);			/*			 * Add vars used in the join 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!).			 */			vars = pull_var_clause(clause, false);			add_vars_to_targetlist(root, vars, relids);			list_free(vars);			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;	}	/*	 * If the clause has a mergejoinable operator, we may be able to deduce	 * more things from it under the principle of transitivity.	 *	 * If it is not an outer-join qualification nor bubbled up due to an outer	 * join, then the two sides represent equivalent PathKeyItems for path	 * keys: any path that is sorted by one side will also be sorted by the	 * other (as soon as the two rels are joined, that is).  Pass such clauses	 * to add_equijoined_keys.	 *	 * 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 (restrictinfo->mergejoinoperator != InvalidOid)	{		if (maybe_equijoin)			add_equijoined_keys(root, restrictinfo);		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);			}			else 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);			}

⌨️ 快捷键说明

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