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

📄 createplan.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
							  otherclauses,							  outer_plan,							  inner_plan,							  best_path->jointype);	copy_path_costsize(&join_plan->join.plan, &best_path->path);	return join_plan;}static MergeJoin *create_mergejoin_plan(PlannerInfo *root,					  MergePath *best_path,					  Plan *outer_plan,					  Plan *inner_plan){	List	   *tlist = build_relation_tlist(best_path->jpath.path.parent);	List	   *joinclauses;	List	   *otherclauses;	List	   *mergeclauses;	MergeJoin  *join_plan;	/* Get the join qual clauses (in plain expression form) */	if (IS_OUTER_JOIN(best_path->jpath.jointype))	{		get_actual_join_clauses(best_path->jpath.joinrestrictinfo,								&joinclauses, &otherclauses);	}	else	{		/* We can treat all clauses alike for an inner join */		joinclauses = get_actual_clauses(best_path->jpath.joinrestrictinfo);		otherclauses = NIL;	}	/*	 * Remove the mergeclauses from the list of join qual clauses, leaving the	 * list of quals that must be checked as qpquals.	 */	mergeclauses = get_actual_clauses(best_path->path_mergeclauses);	joinclauses = list_difference(joinclauses, mergeclauses);	/*	 * Rearrange mergeclauses, if needed, so that the outer variable is always	 * on the left.	 */	mergeclauses = get_switched_clauses(best_path->path_mergeclauses,							 best_path->jpath.outerjoinpath->parent->relids);	/* Sort clauses into best execution order */	/* NB: do NOT reorder the mergeclauses */	joinclauses = order_qual_clauses(root, joinclauses);	otherclauses = order_qual_clauses(root, otherclauses);	/*	 * Create explicit sort nodes for the outer and inner join paths if	 * necessary.  The sort cost was already accounted for in the path. Make	 * sure there are no excess columns in the inputs if sorting.	 */	if (best_path->outersortkeys)	{		disuse_physical_tlist(outer_plan, best_path->jpath.outerjoinpath);		outer_plan = (Plan *)			make_sort_from_pathkeys(root,									outer_plan,									best_path->outersortkeys);	}	if (best_path->innersortkeys)	{		disuse_physical_tlist(inner_plan, best_path->jpath.innerjoinpath);		inner_plan = (Plan *)			make_sort_from_pathkeys(root,									inner_plan,									best_path->innersortkeys);	}	/*	 * Now we can build the mergejoin node.	 */	join_plan = make_mergejoin(tlist,							   joinclauses,							   otherclauses,							   mergeclauses,							   outer_plan,							   inner_plan,							   best_path->jpath.jointype);	copy_path_costsize(&join_plan->join.plan, &best_path->jpath.path);	return join_plan;}static HashJoin *create_hashjoin_plan(PlannerInfo *root,					 HashPath *best_path,					 Plan *outer_plan,					 Plan *inner_plan){	List	   *tlist = build_relation_tlist(best_path->jpath.path.parent);	List	   *joinclauses;	List	   *otherclauses;	List	   *hashclauses;	HashJoin   *join_plan;	Hash	   *hash_plan;	/* Get the join qual clauses (in plain expression form) */	if (IS_OUTER_JOIN(best_path->jpath.jointype))	{		get_actual_join_clauses(best_path->jpath.joinrestrictinfo,								&joinclauses, &otherclauses);	}	else	{		/* We can treat all clauses alike for an inner join */		joinclauses = get_actual_clauses(best_path->jpath.joinrestrictinfo);		otherclauses = NIL;	}	/*	 * Remove the hashclauses from the list of join qual clauses, leaving the	 * list of quals that must be checked as qpquals.	 */	hashclauses = get_actual_clauses(best_path->path_hashclauses);	joinclauses = list_difference(joinclauses, hashclauses);	/*	 * Rearrange hashclauses, if needed, so that the outer variable is always	 * on the left.	 */	hashclauses = get_switched_clauses(best_path->path_hashclauses,							 best_path->jpath.outerjoinpath->parent->relids);	/* Sort clauses into best execution order */	joinclauses = order_qual_clauses(root, joinclauses);	otherclauses = order_qual_clauses(root, otherclauses);	hashclauses = order_qual_clauses(root, hashclauses);	/* We don't want any excess columns in the hashed tuples */	disuse_physical_tlist(inner_plan, best_path->jpath.innerjoinpath);	/*	 * Build the hash node and hash join node.	 */	hash_plan = make_hash(inner_plan);	join_plan = make_hashjoin(tlist,							  joinclauses,							  otherclauses,							  hashclauses,							  outer_plan,							  (Plan *) hash_plan,							  best_path->jpath.jointype);	copy_path_costsize(&join_plan->join.plan, &best_path->jpath.path);	return join_plan;}/***************************************************************************** * *	SUPPORTING ROUTINES * *****************************************************************************//* * fix_indexqual_references *	  Adjust indexqual clauses to the form the executor's indexqual *	  machinery needs, and check for recheckable (lossy) index conditions. * * We have five tasks here: *	* Remove RestrictInfo nodes from the input clauses. *	* Index keys must be represented by Var nodes with varattno set to the *	  index's attribute number, not the attribute number in the original rel. *	* If the index key is on the right, commute the clause to put it on the *	  left. *	* We must construct lists of operator strategy numbers and subtypes *	  for the top-level operators of each index clause. *	* We must detect any lossy index operators.  The API is that we return *	  a list of the input clauses whose operators are NOT lossy. * * fixed_indexquals receives a modified copy of the indexquals list --- the * original is not changed.  Note also that the copy shares no substructure * with the original; this is needed in case there is a subplan in it (we need * two separate copies of the subplan tree, or things will go awry). * * nonlossy_indexquals receives a list of the original input clauses (with * RestrictInfos) that contain non-lossy operators. * * indexstrategy receives an integer list of strategy numbers. * indexsubtype receives an OID list of strategy subtypes. */static voidfix_indexqual_references(List *indexquals, IndexPath *index_path,						 List **fixed_indexquals,						 List **nonlossy_indexquals,						 List **indexstrategy,						 List **indexsubtype){	IndexOptInfo *index = index_path->indexinfo;	ListCell   *l;	*fixed_indexquals = NIL;	*nonlossy_indexquals = NIL;	*indexstrategy = NIL;	*indexsubtype = NIL;	/*	 * For each qual clause, commute if needed to put the indexkey operand on	 * the left, and then fix its varattno.  (We do not need to change the	 * other side of the clause.)  Then determine the operator's strategy	 * number and subtype number, and check for lossy index behavior.	 */	foreach(l, indexquals)	{		RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);		OpExpr	   *clause;		OpExpr	   *newclause;		Oid			opclass;		int			stratno;		Oid			stratsubtype;		bool		recheck;		Assert(IsA(rinfo, RestrictInfo));		clause = (OpExpr *) rinfo->clause;		if (!IsA(clause, OpExpr) ||			list_length(clause->args) != 2)			elog(ERROR, "indexqual clause is not binary opclause");		/*		 * Make a copy that will become the fixed clause.		 *		 * We used to try to do a shallow copy here, but that fails if there		 * is a subplan in the arguments of the opclause.  So just do a full		 * copy.		 */		newclause = (OpExpr *) copyObject((Node *) clause);		/*		 * Check to see if the indexkey is on the right; if so, commute the		 * clause.	The indexkey should be the side that refers to (only) the		 * base relation.		 */		if (!bms_equal(rinfo->left_relids, index->rel->relids))			CommuteClause(newclause);		/*		 * Now, determine which index attribute this is, change the indexkey		 * operand as needed, and get the index opclass.		 */		linitial(newclause->args) =			fix_indexqual_operand(linitial(newclause->args),								  index,								  &opclass);		*fixed_indexquals = lappend(*fixed_indexquals, newclause);		/*		 * Look up the (possibly commuted) operator in the operator class to		 * get its strategy numbers and the recheck indicator.	This also		 * double-checks that we found an operator matching the index.		 */		get_op_opclass_properties(newclause->opno, opclass,								  &stratno, &stratsubtype, &recheck);		*indexstrategy = lappend_int(*indexstrategy, stratno);		*indexsubtype = lappend_oid(*indexsubtype, stratsubtype);		/* If it's not lossy, add to nonlossy_indexquals */		if (!recheck)			*nonlossy_indexquals = lappend(*nonlossy_indexquals, rinfo);	}}static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass){	/*	 * We represent index keys by Var nodes having the varno of the base table	 * but varattno equal to the index's attribute number (index column	 * position).  This is a bit hokey ... would be cleaner to use a	 * special-purpose node type that could not be mistaken for a regular Var.	 * But it will do for now.	 */	Var		   *result;	int			pos;	ListCell   *indexpr_item;	/*	 * Remove any binary-compatible relabeling of the indexkey	 */	if (IsA(node, RelabelType))		node = (Node *) ((RelabelType *) node)->arg;	if (IsA(node, Var) &&		((Var *) node)->varno == index->rel->relid)	{		/* Try to match against simple index columns */		int			varatt = ((Var *) node)->varattno;		if (varatt != 0)		{			for (pos = 0; pos < index->ncolumns; pos++)			{				if (index->indexkeys[pos] == varatt)				{					result = (Var *) copyObject(node);					result->varattno = pos + 1;					/* return the correct opclass, too */					*opclass = index->classlist[pos];					return (Node *) result;				}			}		}	}	/* Try to match against index expressions */	indexpr_item = list_head(index->indexprs);	for (pos = 0; pos < index->ncolumns; pos++)	{		if (index->indexkeys[pos] == 0)		{			Node	   *indexkey;			if (indexpr_item == NULL)				elog(ERROR, "too few entries in indexprs list");			indexkey = (Node *) lfirst(indexpr_item);			if (indexkey && IsA(indexkey, RelabelType))				indexkey = (Node *) ((RelabelType *) indexkey)->arg;			if (equal(node, indexkey))			{				/* Found a match */				result = makeVar(index->rel->relid, pos + 1,								 exprType(lfirst(indexpr_item)), -1,								 0);				/* return the correct opclass, too */				*opclass = index->classlist[pos];				return (Node *) result;			}			indexpr_item = lnext(indexpr_item);		}	}	/* Ooops... */	elog(ERROR, "node is not an index attribute");	*opclass = InvalidOid;		/* keep compiler quiet */	return NULL;}/* * get_switched_clauses *	  Given a list of merge or hash joinclauses (as RestrictInfo nodes), *	  extract the bare clauses, and rearrange the elements within the *	  clauses, if needed, so the outer join variable is on the left and *	  the inner is on the right.  The original data structure is not touched; *	  a modified list is returned. */static List *get_switched_clauses(List *clauses, Relids outerrelids){	List	   *t_list = NIL;	ListCell   *l;	foreach(l, clauses)	{		RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);		OpExpr	   *clause = (OpExpr *) restrictinfo->clause;		Assert(is_opclause(clause));		if (bms_is_subset(restrictinfo->right_relids, outerrelids))		{			/*			 * Duplicate just enough of the structure to allow commuting the			 * clause without changing the original list.  Could use			 * copyObject, but a complete deep copy is overkill.			 */			OpExpr	   *temp = makeNode(OpExpr);			temp->opno = clause->opno;			temp->opfuncid = InvalidOid;			temp->opresulttype = clause->opresulttype;			temp->opretset = clause->opretset;			temp->args = list_copy(clause->args);			/* Commute it --- note this modifies the temp node in-place. */			CommuteClause(temp);			t_list = lappend(t_list, temp);		}		else			t_list = lappend(t_list, clause);	}	return t_list;}/* * order_qual_clauses *		Given a list of qual clauses that will all be evaluated at the same *		plan node, sort the list into the order we want to check the quals *		in at runtime. * * Ideally the order should be driven by a combination of execution cost and * selectivity, but unfortunately we have so little information about * execution cost of operators that it's really hard to do anything smart. * For now, we just move any quals that contain SubPlan references (but not * InitPlan references) to the end of the list. */List *order_qual_clauses(PlannerInfo *root, List *clauses){	List	   *nosubplans;	List	   *withsubplans;	ListCell   *l;	/* No need to work hard if the query is subselect-free */	if (!root->parse->hasSubLinks)		return clauses;	nosubplans = NIL;	withsubplans = NIL;	foreach(l, clauses)	{		Node	   *clause = (Node *) lfirst(l);		if (contain_subplans(clause))			withsubplans = lappend(withsubplans, clause);		else			nosubplans = lappend(nosubplans, clause);	}	return list_concat(nosubplans, withsubplans);}/* * Copy cost and size info from a Path node to the Plan node created from it. * The executor won't use this info, but it's needed by EXPLAIN. */static voidcopy_path_costsize(Plan *dest, Path *src){	if (src)	{		dest->startup_cost = src->startup_cost;		dest->total_cost = src->total_cost;		dest->plan_rows = src->parent->rows;		dest->plan_width = src->parent->width;	}	else	{		dest->startup_cost = 0;		dest->total_cost = 0;

⌨️ 快捷键说明

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