allpaths.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,290 行 · 第 1/3 页

C
1,290
字号
 * AppendPath with no members (see also IS_DUMMY_PATH macro). */static voidset_dummy_rel_pathlist(RelOptInfo *rel){	/* Set dummy size estimates --- we leave attr_widths[] as zeroes */	rel->rows = 0;	rel->width = 0;	add_path(rel, (Path *) create_append_path(rel, NIL));	/* Select cheapest path (pretty easy in this case...) */	set_cheapest(rel);}/* quick-and-dirty test to see if any joining is needed */static boolhas_multiple_baserels(PlannerInfo *root){	int			num_base_rels = 0;	Index		rti;	for (rti = 1; rti < root->simple_rel_array_size; rti++)	{		RelOptInfo *brel = root->simple_rel_array[rti];		if (brel == NULL)			continue;		/* ignore RTEs that are "other rels" */		if (brel->reloptkind == RELOPT_BASEREL)			if (++num_base_rels > 1)				return true;	}	return false;}/* * set_subquery_pathlist *		Build the (single) access path for a subquery RTE */static voidset_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,					  Index rti, RangeTblEntry *rte){	Query	   *parse = root->parse;	Query	   *subquery = rte->subquery;	bool	   *differentTypes;	double		tuple_fraction;	PlannerInfo *subroot;	List	   *pathkeys;	/* We need a workspace for keeping track of set-op type coercions */	differentTypes = (bool *)		palloc0((list_length(subquery->targetList) + 1) * sizeof(bool));	/*	 * If there are any restriction clauses that have been attached to the	 * subquery relation, consider pushing them down to become WHERE or HAVING	 * quals of the subquery itself.  This transformation is useful because it	 * may allow us to generate a better plan for the subquery than evaluating	 * all the subquery output rows and then filtering them.	 *	 * There are several cases where we cannot push down clauses. Restrictions	 * involving the subquery are checked by subquery_is_pushdown_safe().	 * Restrictions on individual clauses are checked by	 * qual_is_pushdown_safe().  Also, we don't want to push down	 * pseudoconstant clauses; better to have the gating node above the	 * subquery.	 *	 * Non-pushed-down clauses will get evaluated as qpquals of the	 * SubqueryScan node.	 *	 * XXX Are there any cases where we want to make a policy decision not to	 * push down a pushable qual, because it'd result in a worse plan?	 */	if (rel->baserestrictinfo != NIL &&		subquery_is_pushdown_safe(subquery, subquery, differentTypes))	{		/* OK to consider pushing down individual quals */		List	   *upperrestrictlist = NIL;		ListCell   *l;		foreach(l, rel->baserestrictinfo)		{			RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);			Node	   *clause = (Node *) rinfo->clause;			if (!rinfo->pseudoconstant &&				qual_is_pushdown_safe(subquery, rti, clause, differentTypes))			{				/* Push it down */				subquery_push_qual(subquery, rte, rti, clause);			}			else			{				/* Keep it in the upper query */				upperrestrictlist = lappend(upperrestrictlist, rinfo);			}		}		rel->baserestrictinfo = upperrestrictlist;	}	pfree(differentTypes);	/*	 * We can safely pass the outer tuple_fraction down to the subquery if the	 * outer level has no joining, aggregation, or sorting to do. Otherwise	 * we'd better tell the subquery to plan for full retrieval. (XXX This	 * could probably be made more intelligent ...)	 */	if (parse->hasAggs ||		parse->groupClause ||		parse->havingQual ||		parse->distinctClause ||		parse->sortClause ||		has_multiple_baserels(root))		tuple_fraction = 0.0;	/* default case */	else		tuple_fraction = root->tuple_fraction;	/* Generate the plan for the subquery */	rel->subplan = subquery_planner(root->glob, subquery,									root->query_level + 1,									tuple_fraction,									&subroot);	rel->subrtable = subroot->parse->rtable;	/* Copy number of output rows from subplan */	rel->tuples = rel->subplan->plan_rows;	/* Mark rel with estimated output rows, width, etc */	set_baserel_size_estimates(root, rel);	/* Convert subquery pathkeys to outer representation */	pathkeys = convert_subquery_pathkeys(root, rel, subroot->query_pathkeys);	/* Generate appropriate path */	add_path(rel, create_subqueryscan_path(rel, pathkeys));	/* Select cheapest path (pretty easy in this case...) */	set_cheapest(rel);}/* * set_function_pathlist *		Build the (single) access path for a function RTE */static voidset_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte){	/* Mark rel with estimated output rows, width, etc */	set_function_size_estimates(root, rel);	/* Generate appropriate path */	add_path(rel, create_functionscan_path(root, rel));	/* Select cheapest path (pretty easy in this case...) */	set_cheapest(rel);}/* * set_values_pathlist *		Build the (single) access path for a VALUES RTE */static voidset_values_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte){	/* Mark rel with estimated output rows, width, etc */	set_values_size_estimates(root, rel);	/* Generate appropriate path */	add_path(rel, create_valuesscan_path(root, rel));	/* Select cheapest path (pretty easy in this case...) */	set_cheapest(rel);}/* * make_rel_from_joinlist *	  Build access paths using a "joinlist" to guide the join path search. * * See comments for deconstruct_jointree() for definition of the joinlist * data structure. */static RelOptInfo *make_rel_from_joinlist(PlannerInfo *root, List *joinlist){	int			levels_needed;	List	   *initial_rels;	ListCell   *jl;	/*	 * Count the number of child joinlist nodes.  This is the depth of the	 * dynamic-programming algorithm we must employ to consider all ways of	 * joining the child nodes.	 */	levels_needed = list_length(joinlist);	if (levels_needed <= 0)		return NULL;			/* nothing to do? */	/*	 * Construct a list of rels corresponding to the child joinlist nodes.	 * This may contain both base rels and rels constructed according to	 * sub-joinlists.	 */	initial_rels = NIL;	foreach(jl, joinlist)	{		Node	   *jlnode = (Node *) lfirst(jl);		RelOptInfo *thisrel;		if (IsA(jlnode, RangeTblRef))		{			int			varno = ((RangeTblRef *) jlnode)->rtindex;			thisrel = find_base_rel(root, varno);		}		else if (IsA(jlnode, List))		{			/* Recurse to handle subproblem */			thisrel = make_rel_from_joinlist(root, (List *) jlnode);		}		else		{			elog(ERROR, "unrecognized joinlist node type: %d",				 (int) nodeTag(jlnode));			thisrel = NULL;		/* keep compiler quiet */		}		initial_rels = lappend(initial_rels, thisrel);	}	if (levels_needed == 1)	{		/*		 * Single joinlist node, so we're done.		 */		return (RelOptInfo *) linitial(initial_rels);	}	else	{		/*		 * Consider the different orders in which we could join the rels,		 * using a plugin, GEQO, or the regular join search code.		 *		 * We put the initial_rels list into a PlannerInfo field because		 * has_legal_joinclause() needs to look at it (ugly :-().		 */		root->initial_rels = initial_rels;		if (join_search_hook)			return (*join_search_hook) (root, levels_needed, initial_rels);		else if (enable_geqo && levels_needed >= geqo_threshold)			return geqo(root, levels_needed, initial_rels);		else			return standard_join_search(root, levels_needed, initial_rels);	}}/* * standard_join_search *	  Find possible joinpaths for a query by successively finding ways *	  to join component relations into join relations. * * 'levels_needed' is the number of iterations needed, ie, the number of *		independent jointree items in the query.  This is > 1. * * 'initial_rels' is a list of RelOptInfo nodes for each independent *		jointree item.	These are the components to be joined together. *		Note that levels_needed == list_length(initial_rels). * * Returns the final level of join relations, i.e., the relation that is * the result of joining all the original relations together. * At least one implementation path must be provided for this relation and * all required sub-relations. * * To support loadable plugins that modify planner behavior by changing the * join searching algorithm, we provide a hook variable that lets a plugin * replace or supplement this function.  Any such hook must return the same * final join relation as the standard code would, but it might have a * different set of implementation paths attached, and only the sub-joinrels * needed for these paths need have been instantiated. * * Note to plugin authors: the functions invoked during standard_join_search() * modify root->join_rel_list and root->join_rel_hash.	If you want to do more * than one join-order search, you'll probably need to save and restore the * original states of those data structures.  See geqo_eval() for an example. */RelOptInfo *standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels){	List	  **joinitems;	int			lev;	RelOptInfo *rel;	/*	 * We employ a simple "dynamic programming" algorithm: we first find all	 * ways to build joins of two jointree items, then all ways to build joins	 * of three items (from two-item joins and single items), then four-item	 * joins, and so on until we have considered all ways to join all the	 * items into one rel.	 *	 * joinitems[j] is a list of all the j-item rels.  Initially we set	 * joinitems[1] to represent all the single-jointree-item relations.	 */	joinitems = (List **) palloc0((levels_needed + 1) * sizeof(List *));	joinitems[1] = initial_rels;	for (lev = 2; lev <= levels_needed; lev++)	{		ListCell   *x;		/*		 * Determine all possible pairs of relations to be joined at this		 * level, and build paths for making each one from every available		 * pair of lower-level relations.		 */		joinitems[lev] = join_search_one_level(root, lev, joinitems);		/*		 * Do cleanup work on each just-processed rel.		 */		foreach(x, joinitems[lev])		{			rel = (RelOptInfo *) lfirst(x);			/* Find and save the cheapest paths for this rel */			set_cheapest(rel);#ifdef OPTIMIZER_DEBUG			debug_print_rel(root, rel);#endif		}	}	/*	 * We should have a single rel at the final level.	 */	if (joinitems[levels_needed] == NIL)		elog(ERROR, "failed to build any %d-way joins", levels_needed);	Assert(list_length(joinitems[levels_needed]) == 1);	rel = (RelOptInfo *) linitial(joinitems[levels_needed]);	return rel;}/***************************************************************************** *			PUSHING QUALS DOWN INTO SUBQUERIES *****************************************************************************//* * subquery_is_pushdown_safe - is a subquery safe for pushing down quals? * * subquery is the particular component query being checked.  topquery * is the top component of a set-operations tree (the same Query if no * set-op is involved). * * Conditions checked here: * * 1. If the subquery has a LIMIT clause, we must not push down any quals, * since that could change the set of rows returned. * * 2. If the subquery contains EXCEPT or EXCEPT ALL set ops we cannot push * quals into it, because that would change the results. * * 3. For subqueries using UNION/UNION ALL/INTERSECT/INTERSECT ALL, we can * push quals into each component query, but the quals can only reference * subquery columns that suffer no type coercions in the set operation. * Otherwise there are possible semantic gotchas.  So, we check the * component queries to see if any of them have different output types; * differentTypes[k] is set true if column k has different type in any * component. */static boolsubquery_is_pushdown_safe(Query *subquery, Query *topquery,						  bool *differentTypes){	SetOperationStmt *topop;	/* Check point 1 */	if (subquery->limitOffset != NULL || subquery->limitCount != NULL)		return false;	/* Are we at top level, or looking at a setop component? */	if (subquery == topquery)	{		/* Top level, so check any component queries */		if (subquery->setOperations != NULL)			if (!recurse_pushdown_safe(subquery->setOperations, topquery,									   differentTypes))				return false;	}	else	{		/* Setop component must not have more components (too weird) */		if (subquery->setOperations != NULL)			return false;		/* Check whether setop component output types match top level */		topop = (SetOperationStmt *) topquery->setOperations;		Assert(topop && IsA(topop, SetOperationStmt));		compare_tlist_datatypes(subquery->targetList,								topop->colTypes,								differentTypes);	}	return true;}/* * Helper routine to recurse through setOperations tree */static boolrecurse_pushdown_safe(Node *setOp, Query *topquery,					  bool *differentTypes){	if (IsA(setOp, RangeTblRef))	{		RangeTblRef *rtr = (RangeTblRef *) setOp;		RangeTblEntry *rte = rt_fetch(rtr->rtindex, topquery->rtable);		Query	   *subquery = rte->subquery;		Assert(subquery != NULL);		return subquery_is_pushdown_safe(subquery, topquery, differentTypes);	}	else if (IsA(setOp, SetOperationStmt))	{		SetOperationStmt *op = (SetOperationStmt *) setOp;

⌨️ 快捷键说明

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