initsplan.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 974 行 · 第 1/3 页

C
974
字号
		 * Presently the executor cannot support FOR UPDATE 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.		 * 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 (intMember(relno, root->rowMarks))				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("SELECT FOR UPDATE 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 'RestrictInfo' or 'JoinInfo' field *	  (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 * 'ispusheddown': if TRUE, force the clause to be marked 'ispusheddown' *		(this indicates the clause came from a FromExpr, not a JoinExpr) * 'isdeduced': TRUE if the qual came from implied-equality deduction * '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 * 'ispusheddown' will be TRUE. */static voiddistribute_qual_to_rels(Query *root, Node *clause,						bool ispusheddown,						bool isdeduced,						Relids outerjoin_nonnullable,						Relids qualscope){	RestrictInfo *restrictinfo = makeNode(RestrictInfo);	RelOptInfo *rel;	Relids		relids;	List	   *vars;	bool		can_be_equijoin;	restrictinfo->clause = (Expr *) clause;	restrictinfo->subclauseindices = NIL;	restrictinfo->eval_cost.startup = -1;		/* not computed until												 * needed */	restrictinfo->this_selec = -1;		/* not computed until needed */	restrictinfo->left_relids = NULL;	/* set below, if join clause */	restrictinfo->right_relids = NULL;	restrictinfo->mergejoinoperator = InvalidOid;	restrictinfo->left_sortop = InvalidOid;	restrictinfo->right_sortop = InvalidOid;	restrictinfo->left_pathkey = NIL;	/* not computable yet */	restrictinfo->right_pathkey = NIL;	restrictinfo->left_mergescansel = -1;		/* not computed until												 * needed */	restrictinfo->right_mergescansel = -1;	restrictinfo->hashjoinoperator = InvalidOid;	restrictinfo->left_bucketsize = -1; /* not computed until needed */	restrictinfo->right_bucketsize = -1;	/*	 * Retrieve all relids and vars contained within the clause.	 */	clause_get_relids_vars(clause, &relids, &vars);	/*	 * 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 (isdeduced)	{		/*		 * If the qual came from implied-equality deduction, we can		 * evaluate the qual at its natural semantic level.  It is not		 * affected by any outer-join rules (else we'd not have decided		 * the vars were equal).		 */		Assert(bms_equal(relids, qualscope));		can_be_equijoin = true;	}	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.		 */		relids = qualscope;		can_be_equijoin = false;	}	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;		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);		}		bms_free(tmprelids);		if (bms_is_subset(addrelids, relids))		{			/* Qual is not affected by any outer-join restriction */			can_be_equijoin = true;		}		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.			 */			can_be_equijoin = false;		}		bms_free(addrelids);	}	/*	 * 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".	 */	restrictinfo->ispusheddown = ispusheddown || !bms_equal(relids,															qualscope);	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.			 */			if (can_be_equijoin)				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 (!isdeduced ||			!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.   Set additional RestrictInfo fields for			 * joining.  First, does it look like a normal join clause,			 * i.e., a binary operator relating expressions that come from			 * distinct relations?	If so we might be able to use it in a			 * join algorithm.			 */			if (is_opclause(clause) && length(((OpExpr *) clause)->args) == 2)			{				Relids		left_relids;				Relids		right_relids;				left_relids = pull_varnos(get_leftop((Expr *) clause));				right_relids = pull_varnos(get_rightop((Expr *) clause));				if (!bms_is_empty(left_relids) &&					!bms_is_empty(right_relids) &&					!bms_overlap(left_relids, right_relids))				{					restrictinfo->left_relids = left_relids;					restrictinfo->right_relids = right_relids;				}			}			/*			 * Now 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!).			 */			add_vars_to_targetlist(root, vars, 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;	}	/*	 * If the clause has a mergejoinable operator, and 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).  Record the key	 * equivalence for future use.	(We can skip this for a deduced	 * clause, since the keys are already known equivalent in that case.)	 */	if (can_be_equijoin && restrictinfo->mergejoinoperator != InvalidOid &&		!isdeduced)		add_equijoined_keys(root, restrictinfo);}/* * process_implied_equality *	  Check to see whether we already have a restrictinfo item that says *	  item1 = item2, and create one if not; or if delete_it is true, *	  remove any such restrictinfo item. * * This processing is a consequence of transitivity of mergejoin equality: * if we have mergejoinable clauses A = B and B = C, we can deduce A = C * (where = is an appropriate mergejoinable operator).	See path/pathkeys.c * for more details. */voidprocess_implied_equality(Query *root,						 Node *item1, Node *item2,						 Oid sortop1, Oid sortop2,						 Relids item1_relids, Relids item2_relids,						 bool delete_it){	Relids		relids;	BMS_Membership membership;	RelOptInfo *rel1;	List	   *restrictlist;

⌨️ 快捷键说明

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