planner.c

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

C
1,553
字号
											numAggs,											result_plan);			/* Hashed aggregation produces randomly-ordered results */			current_pathkeys = NIL;		}		else if (parse->hasAggs)		{			/* Plain aggregate plan --- sort if needed */			AggStrategy aggstrategy;			if (parse->groupClause)			{				if (!pathkeys_contained_in(group_pathkeys, current_pathkeys))				{					result_plan = (Plan *)						make_sort_from_groupcols(parse,												 parse->groupClause,												 groupColIdx,												 result_plan);					current_pathkeys = group_pathkeys;				}				aggstrategy = AGG_SORTED;				/*				 * The AGG node will not change the sort ordering of its				 * groups, so current_pathkeys describes the result too.				 */			}			else			{				aggstrategy = AGG_PLAIN;				/* Result will be only one row anyway; no sort order */				current_pathkeys = NIL;			}			result_plan = (Plan *) make_agg(parse,											tlist,											(List *) parse->havingQual,											aggstrategy,											numGroupCols,											groupColIdx,											numGroups,											numAggs,											result_plan);		}		else		{			/*			 * If there are no Aggs, we shouldn't have any HAVING qual			 * anymore			 */			Assert(parse->havingQual == NULL);			/*			 * If we have a GROUP BY clause, insert a group node (plus the			 * appropriate sort node, if necessary).			 */			if (parse->groupClause)			{				/*				 * Add an explicit sort if we couldn't make the path come				 * out the way the GROUP node needs it.				 */				if (!pathkeys_contained_in(group_pathkeys, current_pathkeys))				{					result_plan = (Plan *)						make_sort_from_groupcols(parse,												 parse->groupClause,												 groupColIdx,												 result_plan);					current_pathkeys = group_pathkeys;				}				result_plan = (Plan *) make_group(parse,												  tlist,												  numGroupCols,												  groupColIdx,												  dNumGroups,												  result_plan);				/* The Group node won't change sort ordering */			}		}	}							/* end of if (setOperations) */	/*	 * If we were not able to make the plan come out in the right order,	 * add an explicit sort step.	 */	if (parse->sortClause)	{		if (!pathkeys_contained_in(sort_pathkeys, current_pathkeys))		{			result_plan = (Plan *)				make_sort_from_sortclauses(parse,										   tlist,										   result_plan,										   parse->sortClause);			current_pathkeys = sort_pathkeys;		}	}	/*	 * If there is a DISTINCT clause, add the UNIQUE node.	 */	if (parse->distinctClause)	{		result_plan = (Plan *) make_unique(tlist, result_plan,										   parse->distinctClause);		/*		 * If there was grouping or aggregation, leave plan_rows as-is		 * (ie, assume the result was already mostly unique).  If not,		 * it's reasonable to assume the UNIQUE filter has effects		 * comparable to GROUP BY.		 */		if (!parse->groupClause && !parse->hasAggs)		{			List	   *distinctExprs;			distinctExprs = get_sortgrouplist_exprs(parse->distinctClause,													parse->targetList);			result_plan->plan_rows = estimate_num_groups(parse,														 distinctExprs,												 result_plan->plan_rows);		}	}	/*	 * Finally, if there is a LIMIT/OFFSET clause, add the LIMIT node.	 */	if (parse->limitOffset || parse->limitCount)	{		result_plan = (Plan *) make_limit(tlist, result_plan,										  parse->limitOffset,										  parse->limitCount);	}	/*	 * Return the actual output ordering in query_pathkeys for possible	 * use by an outer query level.	 */	parse->query_pathkeys = current_pathkeys;	return result_plan;}/* * hash_safe_grouping - are grouping operators hashable? * * We assume hashed aggregation will work if the datatype's equality operator * is marked hashjoinable. */static boolhash_safe_grouping(Query *parse){	List	   *gl;	foreach(gl, parse->groupClause)	{		GroupClause *grpcl = (GroupClause *) lfirst(gl);		TargetEntry *tle = get_sortgroupclause_tle(grpcl, parse->targetList);		Operator	optup;		bool		oprcanhash;		optup = equality_oper(tle->resdom->restype, true);		if (!optup)			return false;		oprcanhash = ((Form_pg_operator) GETSTRUCT(optup))->oprcanhash;		ReleaseSysCache(optup);		if (!oprcanhash)			return false;	}	return true;}/*--------------- * make_subplanTargetList *	  Generate appropriate target list when grouping is required. * * When grouping_planner inserts Aggregate or Group plan nodes above * the result of query_planner, we typically want to pass a different * target list to query_planner than the outer plan nodes should have. * This routine generates the correct target list for the subplan. * * The initial target list passed from the parser already contains entries * for all ORDER BY and GROUP BY expressions, but it will not have entries * for variables used only in HAVING clauses; so we need to add those * variables to the subplan target list.  Also, if we are doing either * grouping or aggregation, we flatten all expressions except GROUP BY items * into their component variables; the other expressions will be computed by * the inserted nodes rather than by the subplan.  For example, * given a query like *		SELECT a+b,SUM(c+d) FROM table GROUP BY a+b; * we want to pass this targetlist to the subplan: *		a,b,c,d,a+b * where the a+b target will be used by the Sort/Group steps, and the * other targets will be used for computing the final results.	(In the * above example we could theoretically suppress the a and b targets and * pass down only c,d,a+b, but it's not really worth the trouble to * eliminate simple var references from the subplan.  We will avoid doing * the extra computation to recompute a+b at the outer level; see * replace_vars_with_subplan_refs() in setrefs.c.) * * If we are grouping or aggregating, *and* there are no non-Var grouping * expressions, then the returned tlist is effectively dummy; we do not * need to force it to be evaluated, because all the Vars it contains * should be present in the output of query_planner anyway. * * 'parse' is the query being processed. * 'tlist' is the query's target list. * 'groupColIdx' receives an array of column numbers for the GROUP BY *			expressions (if there are any) in the subplan's target list. * 'need_tlist_eval' is set true if we really need to evaluate the *			result tlist. * * The result is the targetlist to be passed to the subplan. *--------------- */static List *make_subplanTargetList(Query *parse,					   List *tlist,					   AttrNumber **groupColIdx,					   bool *need_tlist_eval){	List	   *sub_tlist;	List	   *extravars;	int			numCols;	*groupColIdx = NULL;	/*	 * If we're not grouping or aggregating, nothing to do here;	 * query_planner should receive the unmodified target list.	 */	if (!parse->hasAggs && !parse->groupClause)	{		*need_tlist_eval = true;		return tlist;	}	/*	 * Otherwise, start with a "flattened" tlist (having just the vars	 * mentioned in the targetlist and HAVING qual --- but not upper-	 * level Vars; they will be replaced by Params later on).	 */	sub_tlist = flatten_tlist(tlist);	extravars = pull_var_clause(parse->havingQual, false);	sub_tlist = add_to_flat_tlist(sub_tlist, extravars);	freeList(extravars);	*need_tlist_eval = false;	/* only eval if not flat tlist */	/*	 * If grouping, create sub_tlist entries for all GROUP BY expressions	 * (GROUP BY items that are simple Vars should be in the list	 * already), and make an array showing where the group columns are in	 * the sub_tlist.	 */	numCols = length(parse->groupClause);	if (numCols > 0)	{		int			keyno = 0;		AttrNumber *grpColIdx;		List	   *gl;		grpColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);		*groupColIdx = grpColIdx;		foreach(gl, parse->groupClause)		{			GroupClause *grpcl = (GroupClause *) lfirst(gl);			Node	   *groupexpr = get_sortgroupclause_expr(grpcl, tlist);			TargetEntry *te = NULL;			List	   *sl;			/* Find or make a matching sub_tlist entry */			foreach(sl, sub_tlist)			{				te = (TargetEntry *) lfirst(sl);				if (equal(groupexpr, te->expr))					break;			}			if (!sl)			{				te = makeTargetEntry(makeResdom(length(sub_tlist) + 1,												exprType(groupexpr),												exprTypmod(groupexpr),												NULL,												false),									 (Expr *) groupexpr);				sub_tlist = lappend(sub_tlist, te);				*need_tlist_eval = true;		/* it's not flat anymore */			}			/* and save its resno */			grpColIdx[keyno++] = te->resdom->resno;		}	}	return sub_tlist;}/* * locate_grouping_columns *		Locate grouping columns in the tlist chosen by query_planner. * * This is only needed if we don't use the sub_tlist chosen by * make_subplanTargetList.	We have to forget the column indexes found * by that routine and re-locate the grouping vars in the real sub_tlist. */static voidlocate_grouping_columns(Query *parse,						List *tlist,						List *sub_tlist,						AttrNumber *groupColIdx){	int			keyno = 0;	List	   *gl;	/*	 * No work unless grouping.	 */	if (!parse->groupClause)	{		Assert(groupColIdx == NULL);		return;	}	Assert(groupColIdx != NULL);	foreach(gl, parse->groupClause)	{		GroupClause *grpcl = (GroupClause *) lfirst(gl);		Node	   *groupexpr = get_sortgroupclause_expr(grpcl, tlist);		TargetEntry *te = NULL;		List	   *sl;		foreach(sl, sub_tlist)		{			te = (TargetEntry *) lfirst(sl);			if (equal(groupexpr, te->expr))				break;		}		if (!sl)			elog(ERROR, "failed to locate grouping columns");		groupColIdx[keyno++] = te->resdom->resno;	}}/* * postprocess_setop_tlist *	  Fix up targetlist returned by plan_set_operations(). * * We need to transpose sort key info from the orig_tlist into new_tlist. * NOTE: this would not be good enough if we supported resjunk sort keys * for results of set operations --- then, we'd need to project a whole * new tlist to evaluate the resjunk columns.  For now, just ereport if we * find any resjunk columns in orig_tlist. */static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist){	List	   *l;	foreach(l, new_tlist)	{		TargetEntry *new_tle = (TargetEntry *) lfirst(l);		TargetEntry *orig_tle;		/* ignore resjunk columns in setop result */		if (new_tle->resdom->resjunk)			continue;		Assert(orig_tlist != NIL);		orig_tle = (TargetEntry *) lfirst(orig_tlist);		orig_tlist = lnext(orig_tlist);		if (orig_tle->resdom->resjunk)	/* should not happen */			elog(ERROR, "resjunk output columns are not implemented");		Assert(new_tle->resdom->resno == orig_tle->resdom->resno);		Assert(new_tle->resdom->restype == orig_tle->resdom->restype);		new_tle->resdom->ressortgroupref = orig_tle->resdom->ressortgroupref;	}	if (orig_tlist != NIL)		elog(ERROR, "resjunk output columns are not implemented");	return new_tlist;}

⌨️ 快捷键说明

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