allpaths.c

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

C
1,290
字号
/*------------------------------------------------------------------------- * * allpaths.c *	  Routines to find possible search paths for processing a query * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.168.2.2 2008/04/01 00:48:44 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#ifdef OPTIMIZER_DEBUG#include "nodes/print.h"#endif#include "optimizer/clauses.h"#include "optimizer/cost.h"#include "optimizer/geqo.h"#include "optimizer/pathnode.h"#include "optimizer/paths.h"#include "optimizer/plancat.h"#include "optimizer/planner.h"#include "optimizer/prep.h"#include "optimizer/var.h"#include "parser/parse_clause.h"#include "parser/parse_expr.h"#include "parser/parsetree.h"#include "rewrite/rewriteManip.h"/* These parameters are set by GUC */bool		enable_geqo = false;	/* just in case GUC doesn't set it */int			geqo_threshold;/* Hook for plugins to replace standard_join_search() */join_search_hook_type join_search_hook = NULL;static void set_base_rel_pathlists(PlannerInfo *root);static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,				 Index rti, RangeTblEntry *rte);static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,					   RangeTblEntry *rte);static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,						Index rti, RangeTblEntry *rte);static void set_dummy_rel_pathlist(RelOptInfo *rel);static void set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,					  Index rti, RangeTblEntry *rte);static void set_function_pathlist(PlannerInfo *root, RelOptInfo *rel,					  RangeTblEntry *rte);static void set_values_pathlist(PlannerInfo *root, RelOptInfo *rel,					RangeTblEntry *rte);static RelOptInfo *make_rel_from_joinlist(PlannerInfo *root, List *joinlist);static bool subquery_is_pushdown_safe(Query *subquery, Query *topquery,						  bool *differentTypes);static bool recurse_pushdown_safe(Node *setOp, Query *topquery,					  bool *differentTypes);static void compare_tlist_datatypes(List *tlist, List *colTypes,						bool *differentTypes);static bool qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual,					  bool *differentTypes);static void subquery_push_qual(Query *subquery,				   RangeTblEntry *rte, Index rti, Node *qual);static void recurse_push_qual(Node *setOp, Query *topquery,				  RangeTblEntry *rte, Index rti, Node *qual);/* * make_one_rel *	  Finds all possible access paths for executing a query, returning a *	  single rel that represents the join of all base rels in the query. */RelOptInfo *make_one_rel(PlannerInfo *root, List *joinlist){	RelOptInfo *rel;	/*	 * Generate access paths for the base rels.	 */	set_base_rel_pathlists(root);	/*	 * Generate access paths for the entire join tree.	 */	rel = make_rel_from_joinlist(root, joinlist);	/*	 * The result should join all and only the query's base rels.	 */#ifdef USE_ASSERT_CHECKING	{		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;			Assert(brel->relid == rti); /* sanity check on array */			/* ignore RTEs that are "other rels" */			if (brel->reloptkind != RELOPT_BASEREL)				continue;			Assert(bms_is_member(rti, rel->relids));			num_base_rels++;		}		Assert(bms_num_members(rel->relids) == num_base_rels);	}#endif	return rel;}/* * set_base_rel_pathlists *	  Finds all paths available for scanning each base-relation entry. *	  Sequential scan and any available indices are considered. *	  Each useful path is attached to its relation's 'pathlist' field. */static voidset_base_rel_pathlists(PlannerInfo *root){	Index		rti;	for (rti = 1; rti < root->simple_rel_array_size; rti++)	{		RelOptInfo *rel = root->simple_rel_array[rti];		/* there may be empty slots corresponding to non-baserel RTEs */		if (rel == NULL)			continue;		Assert(rel->relid == rti);		/* sanity check on array */		/* ignore RTEs that are "other rels" */		if (rel->reloptkind != RELOPT_BASEREL)			continue;		set_rel_pathlist(root, rel, rti, root->simple_rte_array[rti]);	}}/* * set_rel_pathlist *	  Build access paths for a base relation */static voidset_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,				 Index rti, RangeTblEntry *rte){	if (rte->inh)	{		/* It's an "append relation", process accordingly */		set_append_rel_pathlist(root, rel, rti, rte);	}	else if (rel->rtekind == RTE_SUBQUERY)	{		/* Subquery --- generate a separate plan for it */		set_subquery_pathlist(root, rel, rti, rte);	}	else if (rel->rtekind == RTE_FUNCTION)	{		/* RangeFunction --- generate a separate plan for it */		set_function_pathlist(root, rel, rte);	}	else if (rel->rtekind == RTE_VALUES)	{		/* Values list --- generate a separate plan for it */		set_values_pathlist(root, rel, rte);	}	else	{		/* Plain relation */		Assert(rel->rtekind == RTE_RELATION);		set_plain_rel_pathlist(root, rel, rte);	}#ifdef OPTIMIZER_DEBUG	debug_print_rel(root, rel);#endif}/* * set_plain_rel_pathlist *	  Build access paths for a plain relation (no subquery, no inheritance) */static voidset_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte){	/*	 * If we can prove we don't need to scan the rel via constraint exclusion,	 * set up a single dummy path for it.  We only need to check for regular	 * baserels; if it's an otherrel, CE was already checked in	 * set_append_rel_pathlist().	 */	if (rel->reloptkind == RELOPT_BASEREL &&		relation_excluded_by_constraints(root, rel, rte))	{		set_dummy_rel_pathlist(rel);		return;	}	/* Mark rel with estimated output rows, width, etc */	set_baserel_size_estimates(root, rel);	/* Test any partial indexes of rel for applicability */	check_partial_indexes(root, rel);	/*	 * Check to see if we can extract any restriction conditions from join	 * quals that are OR-of-AND structures.  If so, add them to the rel's	 * restriction list, and recompute the size estimates.	 */	if (create_or_index_quals(root, rel))		set_baserel_size_estimates(root, rel);	/*	 * Generate paths and add them to the rel's pathlist.	 *	 * Note: add_path() will discard any paths that are dominated by another	 * available path, keeping only those paths that are superior along at	 * least one dimension of cost or sortedness.	 */	/* Consider sequential scan */	add_path(rel, create_seqscan_path(root, rel));	/* Consider index scans */	create_index_paths(root, rel);	/* Consider TID scans */	create_tidscan_paths(root, rel);	/* Now find the cheapest of the paths for this rel */	set_cheapest(rel);}/* * set_append_rel_pathlist *	  Build access paths for an "append relation" * * The passed-in rel and RTE represent the entire append relation.	The * relation's contents are computed by appending together the output of * the individual member relations.  Note that in the inheritance case, * the first member relation is actually the same table as is mentioned in * the parent RTE ... but it has a different RTE and RelOptInfo.  This is * a good thing because their outputs are not the same size. */static voidset_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,						Index rti, RangeTblEntry *rte){	int			parentRTindex = rti;	List	   *subpaths = NIL;	ListCell   *l;	/*	 * XXX for now, can't handle inherited expansion of FOR UPDATE/SHARE; can	 * we do better?  (This will take some redesign because the executor	 * currently supposes that every rowMark relation is involved in every row	 * returned by the query.)	 */	if (get_rowmark(root->parse, parentRTindex))		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				 errmsg("SELECT FOR UPDATE/SHARE is not supported for inheritance queries")));	/*	 * Initialize to compute size estimates for whole append relation	 */	rel->rows = 0;	rel->width = 0;	/*	 * Generate access paths for each member relation, and pick the cheapest	 * path for each one.	 */	foreach(l, root->append_rel_list)	{		AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);		int			childRTindex;		RangeTblEntry *childRTE;		RelOptInfo *childrel;		Path	   *childpath;		ListCell   *parentvars;		ListCell   *childvars;		/* append_rel_list contains all append rels; ignore others */		if (appinfo->parent_relid != parentRTindex)			continue;		childRTindex = appinfo->child_relid;		childRTE = root->simple_rte_array[childRTindex];		/*		 * The child rel's RelOptInfo was already created during		 * add_base_rels_to_query.		 */		childrel = find_base_rel(root, childRTindex);		Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);		/*		 * We have to copy the parent's targetlist and quals to the child,		 * with appropriate substitution of variables.	However, only the		 * baserestrictinfo quals are needed before we can check for		 * constraint exclusion; so do that first and then check to see if we		 * can disregard this child.		 */		childrel->baserestrictinfo = (List *)			adjust_appendrel_attrs((Node *) rel->baserestrictinfo,								   appinfo);		if (relation_excluded_by_constraints(root, childrel, childRTE))		{			/*			 * This child need not be scanned, so we can omit it from the			 * appendrel.  Mark it with a dummy cheapest-path though, in case			 * best_appendrel_indexscan() looks at it later.			 */			set_dummy_rel_pathlist(childrel);			continue;		}		/* CE failed, so finish copying targetlist and join quals */		childrel->joininfo = (List *)			adjust_appendrel_attrs((Node *) rel->joininfo,								   appinfo);		childrel->reltargetlist = (List *)			adjust_appendrel_attrs((Node *) rel->reltargetlist,								   appinfo);		/*		 * We have to make child entries in the EquivalenceClass data		 * structures as well.		 */		if (rel->has_eclass_joins)		{			add_child_rel_equivalences(root, appinfo, rel, childrel);			childrel->has_eclass_joins = true;		}		/*		 * Copy the parent's attr_needed data as well, with appropriate		 * adjustment of relids and attribute numbers.		 */		pfree(childrel->attr_needed);		childrel->attr_needed =			adjust_appendrel_attr_needed(rel, appinfo,										 childrel->min_attr,										 childrel->max_attr);		/*		 * Compute the child's access paths, and add the cheapest one to the		 * Append path we are constructing for the parent.		 *		 * It's possible that the child is itself an appendrel, in which case		 * we can "cut out the middleman" and just add its child paths to our		 * own list.  (We don't try to do this earlier because we need to		 * apply both levels of transformation to the quals.)		 */		set_rel_pathlist(root, childrel, childRTindex, childRTE);		childpath = childrel->cheapest_total_path;		if (IsA(childpath, AppendPath))			subpaths = list_concat(subpaths,								   ((AppendPath *) childpath)->subpaths);		else			subpaths = lappend(subpaths, childpath);		/*		 * Propagate size information from the child back to the parent. For		 * simplicity, we use the largest widths from any child as the parent		 * estimates.  (If you want to change this, beware of child		 * attr_widths[] entries that haven't been set and are still 0.)		 */		rel->rows += childrel->rows;		if (childrel->width > rel->width)			rel->width = childrel->width;		forboth(parentvars, rel->reltargetlist,				childvars, childrel->reltargetlist)		{			Var		   *parentvar = (Var *) lfirst(parentvars);			Var		   *childvar = (Var *) lfirst(childvars);			if (IsA(parentvar, Var) &&				IsA(childvar, Var))			{				int			pndx = parentvar->varattno - rel->min_attr;				int			cndx = childvar->varattno - childrel->min_attr;				if (childrel->attr_widths[cndx] > rel->attr_widths[pndx])					rel->attr_widths[pndx] = childrel->attr_widths[cndx];			}		}	}	/*	 * Set "raw tuples" count equal to "rows" for the appendrel; needed	 * because some places assume rel->tuples is valid for any baserel.	 */	rel->tuples = rel->rows;	/*	 * Finally, build Append path and install it as the only access path for	 * 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);}/* * set_dummy_rel_pathlist *	  Build a dummy path for a relation that's been excluded by constraints * * Rather than inventing a special "dummy" path type, we represent this as an

⌨️ 快捷键说明

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