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

📄 initsplan.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
			else 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);			}		}	}}/* * 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(PlannerInfo *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;	ListCell   *itm;	Oid			ltype,				rtype;	Operator	eq_operator;	Form_pg_operator pgopform;	Expr	   *clause;	/* Get set of relids referenced in the two expressions */	relids = bms_union(item1_relids, item2_relids);	membership = bms_membership(relids);	/*	 * generate_implied_equalities() shouldn't call me on two constants.	 */	Assert(membership != BMS_EMPTY_SET);	/*	 * If the exprs involve a single rel, we need to look at that rel's	 * baserestrictinfo list.  If multiple rels, we can scan the joininfo list	 * of any of 'em.	 */	if (membership == BMS_SINGLETON)	{		rel1 = find_base_rel(root, bms_singleton_member(relids));		restrictlist = rel1->baserestrictinfo;	}	else	{		Relids		other_rels;		int			first_rel;		/* Copy relids, find and remove one member */		other_rels = bms_copy(relids);		first_rel = bms_first_member(other_rels);		bms_free(other_rels);		rel1 = find_base_rel(root, first_rel);		restrictlist = rel1->joininfo;	}	/*	 * Scan to see if equality is already known.  If so, we're done in the add	 * case, and done after removing it in the delete case.	 */	foreach(itm, restrictlist)	{		RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(itm);		Node	   *left,				   *right;		if (restrictinfo->mergejoinoperator == InvalidOid)			continue;			/* ignore non-mergejoinable clauses */		/* We now know the restrictinfo clause is a binary opclause */		left = get_leftop(restrictinfo->clause);		right = get_rightop(restrictinfo->clause);		if ((equal(item1, left) && equal(item2, right)) ||			(equal(item2, left) && equal(item1, right)))		{			/* found a matching clause */			if (delete_it)			{				if (membership == BMS_SINGLETON)				{					/* delete it from local restrictinfo list */					rel1->baserestrictinfo = list_delete_ptr(rel1->baserestrictinfo,															 restrictinfo);				}				else				{					/* let joininfo.c do it */					remove_join_clause_from_rels(root, restrictinfo, relids);				}			}			return;				/* done */		}	}	/* Didn't find it.  Done if deletion requested */	if (delete_it)		return;	/*	 * This equality is new information, so construct a clause representing it	 * to add to the query data structures.	 */	ltype = exprType(item1);	rtype = exprType(item2);	eq_operator = compatible_oper(list_make1(makeString("=")),								  ltype, rtype, true);	if (!HeapTupleIsValid(eq_operator))	{		/*		 * Would it be safe to just not add the equality to the query if we		 * have no suitable equality operator for the combination of		 * datatypes?  NO, because sortkey selection may screw up anyway.		 */		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_FUNCTION),		errmsg("could not identify an equality operator for types %s and %s",			   format_type_be(ltype), format_type_be(rtype))));	}	pgopform = (Form_pg_operator) GETSTRUCT(eq_operator);	/*	 * Let's just make sure this appears to be a compatible operator.	 */	if (pgopform->oprlsortop != sortop1 ||		pgopform->oprrsortop != sortop2 ||		pgopform->oprresult != BOOLOID)		ereport(ERROR,				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),				 errmsg("equality operator for types %s and %s should be merge-joinable, but isn't",						format_type_be(ltype), format_type_be(rtype))));	/*	 * Now we can 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(oprid(eq_operator),	/* opno */						   BOOLOID,		/* opresulttype */						   false,		/* opretset */						   (Expr *) copyObject(item1),						   (Expr *) copyObject(item2));	ReleaseSysCache(eq_operator);	/*	 * Push the new clause into all the appropriate restrictinfo lists.	 *	 * Note: we mark the qual "pushed down" to ensure that it can never be	 * taken for an original JOIN/ON clause.	 */	distribute_qual_to_rels(root, (Node *) clause,							true, true, false, NULL, relids);}/* * qual_is_redundant *	  Detect whether an implied-equality qual that turns out to be a *	  restriction clause for a single base relation is redundant with *	  already-known restriction clauses for that rel.  This occurs with, *	  for example, *				SELECT * FROM tab WHERE f1 = f2 AND f2 = f3; *	  We need to suppress the redundant condition to avoid computing *	  too-small selectivity, not to mention wasting time at execution. * * Note: quals of the form "var = const" are never considered redundant, * only those of the form "var = var".	This is needed because when we * have constants in an implied-equality set, we use a different strategy * that suppresses all "var = var" deductions.	We must therefore keep * all the "var = const" quals. */static boolqual_is_redundant(PlannerInfo *root,				  RestrictInfo *restrictinfo,				  List *restrictlist){	Node	   *newleft;	Node	   *newright;	List	   *oldquals;	ListCell   *olditem;	List	   *equalexprs;	bool		someadded;	/* Never redundant unless vars appear on both sides */	if (bms_is_empty(restrictinfo->left_relids) ||		bms_is_empty(restrictinfo->right_relids))		return false;	newleft = get_leftop(restrictinfo->clause);	newright = get_rightop(restrictinfo->clause);	/*	 * Set cached pathkeys.  NB: it is okay to do this now because this	 * routine is only invoked while we are generating implied equalities.	 * Therefore, the equi_key_list is already complete and so we can	 * correctly determine canonical pathkeys.	 */	cache_mergeclause_pathkeys(root, restrictinfo);	/* If different, say "not redundant" (should never happen) */	if (restrictinfo->left_pathkey != restrictinfo->right_pathkey)		return false;	/*	 * Scan existing quals to find those referencing same pathkeys. Usually	 * there will be few, if any, so build a list of just the interesting	 * ones.	 */	oldquals = NIL;	foreach(olditem, restrictlist)	{		RestrictInfo *oldrinfo = (RestrictInfo *) lfirst(olditem);		if (oldrinfo->mergejoinoperator != InvalidOid)		{			cache_mergeclause_pathkeys(root, oldrinfo);			if (restrictinfo->left_pathkey == oldrinfo->left_pathkey &&				restrictinfo->right_pathkey == oldrinfo->right_pathkey)				oldquals = lcons(oldrinfo, oldquals);		}	}	if (oldquals == NIL)		return false;	/*	 * Now, we want to develop a list of exprs that are known equal to the	 * left side of the new qual.  We traverse the old-quals list repeatedly	 * to transitively expand the exprs list.  If at any point we find we can	 * reach the right-side expr of the new qual, we are done.	We give up	 * when we can't expand the equalexprs list any more.	 */	equalexprs = list_make1(newleft);	do	{		someadded = false;		/* cannot use foreach here because of possible list_delete */		olditem = list_head(oldquals);		while (olditem)		{			RestrictInfo *oldrinfo = (RestrictInfo *) lfirst(olditem);			Node	   *oldleft = get_leftop(oldrinfo->clause);			Node	   *oldright = get_rightop(oldrinfo->clause);			Node	   *newguy = NULL;			/* must advance olditem before list_delete possibly pfree's it */			olditem = lnext(olditem);			if (list_member(equalexprs, oldleft))				newguy = oldright;			else if (list_member(equalexprs, oldright))				newguy = oldleft;			else				continue;			if (equal(newguy, newright))				return true;	/* we proved new clause is redundant */			equalexprs = lcons(newguy, equalexprs);			someadded = true;			/*			 * Remove this qual from list, since we don't need it anymore.			 */			oldquals = list_delete_ptr(oldquals, oldrinfo);		}	} while (someadded);	return false;				/* it's not redundant */}/***************************************************************************** * *	 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,				leftOp,				rightOp;	if (!is_opclause(clause))		return;	if (list_length(((OpExpr *) clause)->args) != 2)		return;	opno = ((OpExpr *) clause)->opno;	if (op_mergejoinable(opno,						 &leftOp,						 &rightOp) &&		!contain_volatile_functions((Node *) clause))	{		restrictinfo->mergejoinoperator = opno;		restrictinfo->left_sortop = leftOp;		restrictinfo->right_sortop = rightOp;	}}/* * 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 (!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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -