allpaths.c

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 1,160 行 · 第 1/3 页

C
1,160
字号
	 * the parent rel.	(Note: this is correct even if we have zero or one	 * live subpath due to constraint exclusion.)	 */	add_path(rel, (Path *) create_append_path(rel, subpaths));	/* 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->base_rel_array_size; rti++)	{		RelOptInfo *brel = root->base_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;	List	   *pathkeys;	List	   *subquery_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().	 *	 * 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 (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(subquery, tuple_fraction,									&subquery_pathkeys);	/* 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, subquery_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);}/* * make_fromexpr_rel *	  Build access paths for a FromExpr jointree node. */RelOptInfo *make_fromexpr_rel(PlannerInfo *root, FromExpr *from){	int			levels_needed;	List	   *initial_rels = NIL;	ListCell   *jt;	/*	 * Count the number of child jointree 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(from->fromlist);	if (levels_needed <= 0)		return NULL;			/* nothing to do? */	/*	 * Construct a list of rels corresponding to the child jointree nodes.	 * This may contain both base rels and rels constructed according to	 * explicit JOIN directives.	 */	foreach(jt, from->fromlist)	{		Node	   *jtnode = (Node *) lfirst(jt);		initial_rels = lappend(initial_rels,							   make_jointree_rel(root, jtnode));	}	if (levels_needed == 1)	{		/*		 * Single jointree node, so we're done.		 */		return (RelOptInfo *) linitial(initial_rels);	}	else	{		/*		 * Consider the different orders in which we could join the rels,		 * using either GEQO or regular optimizer.		 */		if (enable_geqo && levels_needed >= geqo_threshold)			return geqo(root, levels_needed, initial_rels);		else			return make_one_rel_by_joins(root, levels_needed, initial_rels);	}}/* * make_one_rel_by_joins *	  Find all 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. * * Returns the final level of join relations, i.e., the relation that is * the result of joining all the original relations together. */static RelOptInfo *make_one_rel_by_joins(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] = make_rels_by_joins(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;		/* EXCEPT is no good */		if (op->op == SETOP_EXCEPT)			return false;		/* Else recurse */		if (!recurse_pushdown_safe(op->larg, topquery, differentTypes))			return false;		if (!recurse_pushdown_safe(op->rarg, topquery, differentTypes))			return false;	}	else	{		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(setOp));	}	return true;}/* * Compare tlist's datatypes against the list of set-operation result types. * For any items that are different, mark the appropriate element of * differentTypes[] to show that this column will have type conversions. */static voidcompare_tlist_datatypes(List *tlist, List *colTypes,						bool *differentTypes){	ListCell   *l;	ListCell   *colType = list_head(colTypes);

⌨️ 快捷键说明

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