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

📄 planner.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
		return NULL;	/*	 * If the query has any join RTEs, replace join alias variables with	 * base-relation variables. We must do this before sublink processing,	 * else sublinks expanded out from join aliases wouldn't get processed.	 */	if (root->hasJoinRTEs)		expr = flatten_join_alias_vars(root, expr);	/*	 * Simplify constant expressions.	 *	 * Note: this also flattens nested AND and OR expressions into N-argument	 * form.  All processing of a qual expression after this point must be	 * careful to maintain AND/OR flatness --- that is, do not generate a tree	 * with AND directly under AND, nor OR directly under OR.	 *	 * Because this is a relatively expensive process, we skip it when the	 * query is trivial, such as "SELECT 2+2;" or "INSERT ... VALUES()". The	 * expression will only be evaluated once anyway, so no point in	 * pre-simplifying; we can't execute it any faster than the executor can,	 * and we will waste cycles copying the tree.  Notice however that we	 * still must do it for quals (to get AND/OR flatness); and if we are in a	 * subquery we should not assume it will be done only once.	 */	if (root->parse->jointree->fromlist != NIL ||		kind == EXPRKIND_QUAL ||		PlannerQueryLevel > 1)		expr = eval_const_expressions(expr);	/*	 * If it's a qual or havingQual, canonicalize it.	 */	if (kind == EXPRKIND_QUAL)	{		expr = (Node *) canonicalize_qual((Expr *) expr);#ifdef OPTIMIZER_DEBUG		printf("After canonicalize_qual()\n");		pprint(expr);#endif	}	/* Expand SubLinks to SubPlans */	if (root->parse->hasSubLinks)		expr = SS_process_sublinks(expr, (kind == EXPRKIND_QUAL));	/*	 * XXX do not insert anything here unless you have grokked the comments in	 * SS_replace_correlation_vars ...	 */	/* Replace uplevel vars with Param nodes */	if (PlannerQueryLevel > 1)		expr = SS_replace_correlation_vars(expr);	/*	 * If it's a qual or havingQual, convert it to implicit-AND format. (We	 * don't want to do this before eval_const_expressions, since the latter	 * would be unable to simplify a top-level AND correctly. Also,	 * SS_process_sublinks expects explicit-AND format.)	 */	if (kind == EXPRKIND_QUAL)		expr = (Node *) make_ands_implicit((Expr *) expr);	return expr;}/* * preprocess_qual_conditions *		Recursively scan the query's jointree and do subquery_planner's *		preprocessing work on each qual condition found therein. */static voidpreprocess_qual_conditions(PlannerInfo *root, Node *jtnode){	if (jtnode == NULL)		return;	if (IsA(jtnode, RangeTblRef))	{		/* nothing to do here */	}	else if (IsA(jtnode, FromExpr))	{		FromExpr   *f = (FromExpr *) jtnode;		ListCell   *l;		foreach(l, f->fromlist)			preprocess_qual_conditions(root, lfirst(l));		f->quals = preprocess_expression(root, f->quals, EXPRKIND_QUAL);	}	else if (IsA(jtnode, JoinExpr))	{		JoinExpr   *j = (JoinExpr *) jtnode;		preprocess_qual_conditions(root, j->larg);		preprocess_qual_conditions(root, j->rarg);		j->quals = preprocess_expression(root, j->quals, EXPRKIND_QUAL);	}	else		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(jtnode));}/*-------------------- * inheritance_planner *	  Generate a plan in the case where the result relation is an *	  inheritance set. * * We have to handle this case differently from cases where a source * relation is an inheritance set.	Source inheritance is expanded at * the bottom of the plan tree (see allpaths.c), but target inheritance * has to be expanded at the top.  The reason is that for UPDATE, each * target relation needs a different targetlist matching its own column * set.  (This is not so critical for DELETE, but for simplicity we treat * inherited DELETE the same way.)	Fortunately, the UPDATE/DELETE target * can never be the nullable side of an outer join, so it's OK to generate * the plan this way. * * inheritlist is an integer list of RT indexes for the result relation set. * * Returns a query plan. *-------------------- */static Plan *inheritance_planner(PlannerInfo *root, List *inheritlist){	Query	   *parse = root->parse;	int			parentRTindex = parse->resultRelation;	Oid			parentOID = getrelid(parentRTindex, parse->rtable);	int			mainrtlength = list_length(parse->rtable);	List	   *subplans = NIL;	List	   *tlist = NIL;	ListCell   *l;	foreach(l, inheritlist)	{		int			childRTindex = lfirst_int(l);		Oid			childOID = getrelid(childRTindex, parse->rtable);		PlannerInfo subroot;		Plan	   *subplan;		/*		 * Generate modified query with this rel as target.  We have to be		 * prepared to translate varnos in in_info_list as well as in the		 * Query proper.		 */		memcpy(&subroot, root, sizeof(PlannerInfo));		subroot.parse = (Query *)			adjust_inherited_attrs((Node *) parse,								   parentRTindex, parentOID,								   childRTindex, childOID);		subroot.in_info_list = (List *)			adjust_inherited_attrs((Node *) root->in_info_list,								   parentRTindex, parentOID,								   childRTindex, childOID);		/* Generate plan */		subplan = grouping_planner(&subroot, 0.0 /* retrieve all tuples */ );		subplans = lappend(subplans, subplan);		/*		 * XXX my goodness this next bit is ugly.  Really need to think about		 * ways to rein in planner's habit of scribbling on its input.		 *		 * Planning of the subquery might have modified the rangetable, either		 * by addition of RTEs due to expansion of inherited source tables, or		 * by changes of the Query structures inside subquery RTEs.  We have		 * to ensure that this gets propagated back to the master copy.		 * However, if we aren't done planning yet, we also need to ensure		 * that subsequent calls to grouping_planner have virgin sub-Queries		 * to work from.  So, if we are at the last list entry, just copy the		 * subquery rangetable back to the master copy; if we are not, then		 * extend the master copy by adding whatever the subquery added.  (We		 * assume these added entries will go untouched by the future		 * grouping_planner calls.	We are also effectively assuming that		 * sub-Queries will get planned identically each time, or at least		 * that the impacts on their rangetables will be the same each time.		 * Did I say this is ugly?)		 */		if (lnext(l) == NULL)			parse->rtable = subroot.parse->rtable;		else		{			int			subrtlength = list_length(subroot.parse->rtable);			if (subrtlength > mainrtlength)			{				List	   *subrt;				subrt = list_copy_tail(subroot.parse->rtable, mainrtlength);				parse->rtable = list_concat(parse->rtable, subrt);				mainrtlength = subrtlength;			}		}		/* Save preprocessed tlist from first rel for use in Append */		if (tlist == NIL)			tlist = subplan->targetlist;	}	/* Save the target-relations list for the executor, too */	parse->resultRelations = inheritlist;	/* Mark result as unordered (probably unnecessary) */	root->query_pathkeys = NIL;	return (Plan *) make_append(subplans, true, tlist);}/*-------------------- * grouping_planner *	  Perform planning steps related to grouping, aggregation, etc. *	  This primarily means adding top-level processing to the basic *	  query plan produced by query_planner. * * tuple_fraction is the fraction of tuples we expect will be retrieved * * tuple_fraction is interpreted as follows: *	  0: expect all tuples to be retrieved (normal case) *	  0 < tuple_fraction < 1: expect the given fraction of tuples available *		from the plan to be retrieved *	  tuple_fraction >= 1: tuple_fraction is the absolute number of tuples *		expected to be retrieved (ie, a LIMIT specification) * * Returns a query plan.  Also, root->query_pathkeys is returned as the * actual output ordering of the plan (in pathkey format). *-------------------- */static Plan *grouping_planner(PlannerInfo *root, double tuple_fraction){	Query	   *parse = root->parse;	List	   *tlist = parse->targetList;	int			offset_est = 0;	int			count_est = 0;	Plan	   *result_plan;	List	   *current_pathkeys;	List	   *sort_pathkeys;	double		dNumGroups = 0;	/* Tweak caller-supplied tuple_fraction if have LIMIT/OFFSET */	if (parse->limitCount || parse->limitOffset)		tuple_fraction = preprocess_limit(root, tuple_fraction,										  &offset_est, &count_est);	if (parse->setOperations)	{		List	   *set_sortclauses;		/*		 * If there's a top-level ORDER BY, assume we have to fetch all the		 * tuples.	This might seem too simplistic given all the hackery below		 * to possibly avoid the sort ... but a nonzero tuple_fraction is only		 * of use to plan_set_operations() when the setop is UNION ALL, and		 * the result of UNION ALL is always unsorted.		 */		if (parse->sortClause)			tuple_fraction = 0.0;		/*		 * Construct the plan for set operations.  The result will not need		 * any work except perhaps a top-level sort and/or LIMIT.		 */		result_plan = plan_set_operations(root, tuple_fraction,										  &set_sortclauses);		/*		 * Calculate pathkeys representing the sort order (if any) of the set		 * operation's result.  We have to do this before overwriting the sort		 * key information...		 */		current_pathkeys = make_pathkeys_for_sortclauses(set_sortclauses,													result_plan->targetlist);		current_pathkeys = canonicalize_pathkeys(root, current_pathkeys);		/*		 * We should not need to call preprocess_targetlist, since we must be		 * in a SELECT query node.	Instead, use the targetlist returned by		 * plan_set_operations (since this tells whether it returned any		 * resjunk columns!), and transfer any sort key information from the		 * original tlist.		 */		Assert(parse->commandType == CMD_SELECT);		tlist = postprocess_setop_tlist(result_plan->targetlist, tlist);		/*		 * Can't handle FOR UPDATE/SHARE here (parser should have checked		 * already, but let's make sure).		 */		if (parse->rowMarks)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT")));		/*		 * Calculate pathkeys that represent result ordering requirements		 */		sort_pathkeys = make_pathkeys_for_sortclauses(parse->sortClause,													  tlist);		sort_pathkeys = canonicalize_pathkeys(root, sort_pathkeys);	}	else	{		/* No set operations, do regular planning */		List	   *sub_tlist;		List	   *group_pathkeys;		AttrNumber *groupColIdx = NULL;		bool		need_tlist_eval = true;		QualCost	tlist_cost;		Path	   *cheapest_path;		Path	   *sorted_path;		Path	   *best_path;		long		numGroups = 0;		AggClauseCounts agg_counts;		int			numGroupCols = list_length(parse->groupClause);		bool		use_hashed_grouping = false;		MemSet(&agg_counts, 0, sizeof(AggClauseCounts));		/* Preprocess targetlist */		tlist = preprocess_targetlist(root, tlist);		/*		 * Generate appropriate target list for subplan; may be different from		 * tlist if grouping or aggregation is needed.		 */		sub_tlist = make_subplanTargetList(root, tlist,										   &groupColIdx, &need_tlist_eval);		/*		 * Calculate pathkeys that represent grouping/ordering requirements.		 * Stash them in PlannerInfo so that query_planner can canonicalize		 * them.		 */		root->group_pathkeys =			make_pathkeys_for_sortclauses(parse->groupClause, tlist);		root->sort_pathkeys =			make_pathkeys_for_sortclauses(parse->sortClause, tlist);		/*		 * Will need actual number of aggregates for estimating costs.		 *		 * Note: we do not attempt to detect duplicate aggregates here; a		 * somewhat-overestimated count is okay for our present purposes.		 *		 * Note: think not that we can turn off hasAggs if we find no aggs. It		 * is possible for constant-expression simplification to remove all		 * explicit references to aggs, but we still have to follow the		 * aggregate semantics (eg, producing only one output row).		 */		if (parse->hasAggs)		{			count_agg_clauses((Node *) tlist, &agg_counts);			count_agg_clauses(parse->havingQual, &agg_counts);		}		/*		 * Figure out whether we need a sorted result from query_planner.		 *		 * If we have a GROUP BY clause, then we want a result sorted properly		 * for grouping.  Otherwise, if there is an ORDER BY clause, we want		 * to sort by the ORDER BY clause.	(Note: if we have both, and ORDER		 * BY is a superset of GROUP BY, it would be tempting to request sort		 * by ORDER BY --- but that might just leave us failing to exploit an		 * available sort order at all. Needs more thought...)		 */		if (parse->groupClause)			root->query_pathkeys = root->group_pathkeys;		else if (parse->sortClause)			root->query_pathkeys = root->sort_pathkeys;		else			root->query_pathkeys = NIL;		/*		 * Generate the best unsorted and presorted paths for this Query (but		 * note there may not be any presorted path).  query_planner will also		 * estimate the number of groups in the query, and canonicalize all		 * the pathkeys.		 */		query_planner(root, sub_tlist, tuple_fraction,					  &cheapest_path, &sorted_path, &dNumGroups);		group_pathkeys = root->group_pathkeys;		sort_pathkeys = root->sort_pathkeys;		/*		 * If grouping, decide whether we want to use hashed grouping.		 */		if (parse->groupClause)		{			use_hashed_grouping =				choose_hashed_grouping(root, tuple_fraction,									   cheapest_path, sorted_path,									   dNumGroups, &agg_counts);			/* Also convert # groups to long int --- but 'ware overflow! */			numGroups = (long) Min(dNumGroups, (double) LONG_MAX);		}		/*		 * Select the best path.  If we are doing hashed grouping, we will		 * always read all the input tuples, so use the cheapest-total path.		 * Otherwise, trust query_planner's decision about which to use.		 */

⌨️ 快捷键说明

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