pathnode.c

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

C
1,297
字号
	IndexPath  *pathnode = makeNode(IndexPath);	RelOptInfo *rel = index->rel;	List	   *indexquals,			   *allclauses;	/*	 * For a join inner scan, there's no point in marking the path with any	 * pathkeys, since it will only ever be used as the inner path of a	 * nestloop, and so its ordering does not matter.  For the same reason we	 * don't really care what order it's scanned in.  (We could expect the	 * caller to supply the correct values, but it's easier to force it here.)	 */	if (outer_rel != NULL)	{		pathkeys = NIL;		indexscandir = NoMovementScanDirection;	}	pathnode->path.pathtype = T_IndexScan;	pathnode->path.parent = rel;	pathnode->path.pathkeys = pathkeys;	/* Convert clauses to indexquals the executor can handle */	indexquals = expand_indexqual_conditions(index, clause_groups);	/* Flatten the clause-groups list to produce indexclauses list */	allclauses = flatten_clausegroups_list(clause_groups);	/* Fill in the pathnode */	pathnode->indexinfo = index;	pathnode->indexclauses = allclauses;	pathnode->indexquals = indexquals;	pathnode->isjoininner = (outer_rel != NULL);	pathnode->indexscandir = indexscandir;	if (outer_rel != NULL)	{		/*		 * We must compute the estimated number of output rows for the		 * indexscan.  This is less than rel->rows because of the additional		 * selectivity of the join clauses.  Since clause_groups may contain		 * both restriction and join clauses, we have to do a set union to get		 * the full set of clauses that must be considered to compute the		 * correct selectivity.  (Without the union operation, we might have		 * some restriction clauses appearing twice, which'd mislead		 * clauselist_selectivity into double-counting their selectivity.		 * However, since RestrictInfo nodes aren't copied when linking them		 * into different lists, it should be sufficient to use pointer		 * comparison to remove duplicates.)		 *		 * Always assume the join type is JOIN_INNER; even if some of the join		 * clauses come from other contexts, that's not our problem.		 */		allclauses = list_union_ptr(rel->baserestrictinfo, allclauses);		pathnode->rows = rel->tuples *			clauselist_selectivity(root,								   allclauses,								   rel->relid,	/* do not use 0! */								   JOIN_INNER);		/* Like costsize.c, force estimate to be at least one row */		pathnode->rows = clamp_row_est(pathnode->rows);	}	else	{		/*		 * The number of rows is the same as the parent rel's estimate, since		 * this isn't a join inner indexscan.		 */		pathnode->rows = rel->rows;	}	cost_index(pathnode, root, index, indexquals, outer_rel);	return pathnode;}/* * create_bitmap_heap_path *	  Creates a path node for a bitmap scan. * * 'bitmapqual' is a tree of IndexPath, BitmapAndPath, and BitmapOrPath nodes. * * If this is a join inner indexscan path, 'outer_rel' is the outer relation, * and all the component IndexPaths should have been costed accordingly. */BitmapHeapPath *create_bitmap_heap_path(PlannerInfo *root,						RelOptInfo *rel,						Path *bitmapqual,						RelOptInfo *outer_rel){	BitmapHeapPath *pathnode = makeNode(BitmapHeapPath);	pathnode->path.pathtype = T_BitmapHeapScan;	pathnode->path.parent = rel;	pathnode->path.pathkeys = NIL;		/* always unordered */	pathnode->bitmapqual = bitmapqual;	pathnode->isjoininner = (outer_rel != NULL);	if (pathnode->isjoininner)	{		/*		 * We must compute the estimated number of output rows for the		 * indexscan.  This is less than rel->rows because of the additional		 * selectivity of the join clauses.  We make use of the selectivity		 * estimated for the bitmap to do this; this isn't really quite right		 * since there may be restriction conditions not included in the		 * bitmap ...		 */		Cost		indexTotalCost;		Selectivity indexSelectivity;		cost_bitmap_tree_node(bitmapqual, &indexTotalCost, &indexSelectivity);		pathnode->rows = rel->tuples * indexSelectivity;		if (pathnode->rows > rel->rows)			pathnode->rows = rel->rows;		/* Like costsize.c, force estimate to be at least one row */		pathnode->rows = clamp_row_est(pathnode->rows);	}	else	{		/*		 * The number of rows is the same as the parent rel's estimate, since		 * this isn't a join inner indexscan.		 */		pathnode->rows = rel->rows;	}	cost_bitmap_heap_scan(&pathnode->path, root, rel, bitmapqual, outer_rel);	return pathnode;}/* * create_bitmap_and_path *	  Creates a path node representing a BitmapAnd. */BitmapAndPath *create_bitmap_and_path(PlannerInfo *root,					   RelOptInfo *rel,					   List *bitmapquals){	BitmapAndPath *pathnode = makeNode(BitmapAndPath);	pathnode->path.pathtype = T_BitmapAnd;	pathnode->path.parent = rel;	pathnode->path.pathkeys = NIL;		/* always unordered */	pathnode->bitmapquals = bitmapquals;	/* this sets bitmapselectivity as well as the regular cost fields: */	cost_bitmap_and_node(pathnode, root);	return pathnode;}/* * create_bitmap_or_path *	  Creates a path node representing a BitmapOr. */BitmapOrPath *create_bitmap_or_path(PlannerInfo *root,					  RelOptInfo *rel,					  List *bitmapquals){	BitmapOrPath *pathnode = makeNode(BitmapOrPath);	pathnode->path.pathtype = T_BitmapOr;	pathnode->path.parent = rel;	pathnode->path.pathkeys = NIL;		/* always unordered */	pathnode->bitmapquals = bitmapquals;	/* this sets bitmapselectivity as well as the regular cost fields: */	cost_bitmap_or_node(pathnode, root);	return pathnode;}/* * create_tidscan_path *	  Creates a path corresponding to a scan by TID, returning the pathnode. */TidPath *create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals){	TidPath    *pathnode = makeNode(TidPath);	pathnode->path.pathtype = T_TidScan;	pathnode->path.parent = rel;	pathnode->path.pathkeys = NIL;	pathnode->tidquals = tidquals;	cost_tidscan(&pathnode->path, root, rel, tidquals);	return pathnode;}/* * create_append_path *	  Creates a path corresponding to an Append plan, returning the *	  pathnode. */AppendPath *create_append_path(RelOptInfo *rel, List *subpaths){	AppendPath *pathnode = makeNode(AppendPath);	ListCell   *l;	pathnode->path.pathtype = T_Append;	pathnode->path.parent = rel;	pathnode->path.pathkeys = NIL;		/* result is always considered										 * unsorted */	pathnode->subpaths = subpaths;	pathnode->path.startup_cost = 0;	pathnode->path.total_cost = 0;	foreach(l, subpaths)	{		Path	   *subpath = (Path *) lfirst(l);		if (l == list_head(subpaths))	/* first node? */			pathnode->path.startup_cost = subpath->startup_cost;		pathnode->path.total_cost += subpath->total_cost;	}	return pathnode;}/* * create_result_path *	  Creates a path representing a Result-and-nothing-else plan. *	  This is only used for the case of a query with an empty jointree. */ResultPath *create_result_path(List *quals){	ResultPath *pathnode = makeNode(ResultPath);	pathnode->path.pathtype = T_Result;	pathnode->path.parent = NULL;	pathnode->path.pathkeys = NIL;	pathnode->quals = quals;	/* Ideally should define cost_result(), but I'm too lazy */	pathnode->path.startup_cost = 0;	pathnode->path.total_cost = cpu_tuple_cost;	/*	 * In theory we should include the qual eval cost as well, but at present	 * that doesn't accomplish much except duplicate work that will be done	 * again in make_result; since this is only used for degenerate cases,	 * nothing interesting will be done with the path cost values...	 */	return pathnode;}/* * create_material_path *	  Creates a path corresponding to a Material plan, returning the *	  pathnode. */MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath){	MaterialPath *pathnode = makeNode(MaterialPath);	pathnode->path.pathtype = T_Material;	pathnode->path.parent = rel;	pathnode->path.pathkeys = subpath->pathkeys;	pathnode->subpath = subpath;	cost_material(&pathnode->path,				  subpath->total_cost,				  rel->rows,				  rel->width);	return pathnode;}/* * create_unique_path *	  Creates a path representing elimination of distinct rows from the *	  input data. * * If used at all, this is likely to be called repeatedly on the same rel; * and the input subpath should always be the same (the cheapest_total path * for the rel).  So we cache the result. */UniquePath *create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath){	UniquePath *pathnode;	Path		sort_path;		/* dummy for result of cost_sort */	Path		agg_path;		/* dummy for result of cost_agg */	MemoryContext oldcontext;	List	   *sub_targetlist;	List	   *in_operators;	ListCell   *l;	int			numCols;	/* Caller made a mistake if subpath isn't cheapest_total */	Assert(subpath == rel->cheapest_total_path);	/* If result already cached, return it */	if (rel->cheapest_unique_path)		return (UniquePath *) rel->cheapest_unique_path;	/*	 * We must ensure path struct is allocated in main planning context;	 * otherwise GEQO memory management causes trouble.  (Compare	 * best_inner_indexscan().)	 */	oldcontext = MemoryContextSwitchTo(root->planner_cxt);	pathnode = makeNode(UniquePath);	/* There is no substructure to allocate, so can switch back right away */	MemoryContextSwitchTo(oldcontext);	pathnode->path.pathtype = T_Unique;	pathnode->path.parent = rel;	/*	 * Treat the output as always unsorted, since we don't necessarily have	 * pathkeys to represent it.	 */	pathnode->path.pathkeys = NIL;	pathnode->subpath = subpath;	/*	 * Try to identify the targetlist that will actually be unique-ified. In	 * current usage, this routine is only used for sub-selects of IN clauses,	 * so we should be able to find the tlist in in_info_list.	Get the IN	 * clause's operators, too, because they determine what "unique" means.	 */	sub_targetlist = NIL;	in_operators = NIL;	foreach(l, root->in_info_list)	{		InClauseInfo *ininfo = (InClauseInfo *) lfirst(l);		if (bms_equal(ininfo->righthand, rel->relids))		{			sub_targetlist = ininfo->sub_targetlist;			in_operators = ininfo->in_operators;			break;		}	}	/*	 * If the input is a subquery whose output must be unique already, then we	 * don't need to do anything.  The test for uniqueness has to consider	 * exactly which columns we are extracting; for example "SELECT DISTINCT	 * x,y" doesn't guarantee that x alone is distinct. So we cannot check for	 * this optimization unless we found our own targetlist above, and it	 * consists only of simple Vars referencing subquery outputs.  (Possibly	 * we could do something with expressions in the subquery outputs, too,	 * but for now keep it simple.)	 */	if (sub_targetlist && rel->rtekind == RTE_SUBQUERY)	{		RangeTblEntry *rte = planner_rt_fetch(rel->relid, root);		List	   *sub_tlist_colnos;		sub_tlist_colnos = translate_sub_tlist(sub_targetlist, rel->relid);		if (sub_tlist_colnos &&			query_is_distinct_for(rte->subquery,								  sub_tlist_colnos, in_operators))		{			pathnode->umethod = UNIQUE_PATH_NOOP;			pathnode->rows = rel->rows;			pathnode->path.startup_cost = subpath->startup_cost;			pathnode->path.total_cost = subpath->total_cost;			pathnode->path.pathkeys = subpath->pathkeys;			rel->cheapest_unique_path = (Path *) pathnode;			return pathnode;		}	}	/*	 * If we know the targetlist, try to estimate number of result rows;	 * otherwise punt.	 */	if (sub_targetlist)	{		pathnode->rows = estimate_num_groups(root, sub_targetlist, rel->rows);		numCols = list_length(sub_targetlist);	}	else	{		pathnode->rows = rel->rows;		numCols = list_length(rel->reltargetlist);	}	/*	 * Estimate cost for sort+unique implementation	 */	cost_sort(&sort_path, root, NIL,			  subpath->total_cost,			  rel->rows,			  rel->width,			  -1.0);	/*	 * Charge one cpu_operator_cost per comparison per input tuple. We assume	 * all columns get compared at most of the tuples.	(XXX probably this is	 * an overestimate.)  This should agree with make_unique.	 */	sort_path.total_cost += cpu_operator_cost * rel->rows * numCols;	/*	 * Is it safe to use a hashed implementation?  If so, estimate and compare	 * costs.  We only try this if we know the IN operators, else we can't	 * check their hashability.	 */	pathnode->umethod = UNIQUE_PATH_SORT;	if (enable_hashagg && in_operators && hash_safe_operators(in_operators))	{		/*		 * Estimate the overhead per hashtable entry at 64 bytes (same as in		 * planner.c).		 */

⌨️ 快捷键说明

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