pathnode.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 863 行 · 第 1/2 页

C
863
字号
	{		Path	   *subpath = (Path *) lfirst(l);		if (l == 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 corresponding to a Result plan, returning the *	  pathnode. */ResultPath *create_result_path(RelOptInfo *rel, Path *subpath, List *constantqual){	ResultPath *pathnode = makeNode(ResultPath);	pathnode->path.pathtype = T_Result;	pathnode->path.parent = rel;	/* may be NULL */	if (subpath)		pathnode->path.pathkeys = subpath->pathkeys;	else		pathnode->path.pathkeys = NIL;	pathnode->subpath = subpath;	pathnode->constantqual = constantqual;	/* Ideally should define cost_result(), but I'm too lazy */	if (subpath)	{		pathnode->path.startup_cost = subpath->startup_cost;		pathnode->path.total_cost = subpath->total_cost;	}	else	{		pathnode->path.startup_cost = 0;		pathnode->path.total_cost = cpu_tuple_cost;	}	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(Query *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	   *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 same context as parent	 * rel; otherwise GEQO memory management causes trouble.  (Compare	 * best_inner_indexscan().)	 */	oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(rel));	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.	 */	sub_targetlist = NIL;	foreach(l, root->in_info_list)	{		InClauseInfo *ininfo = (InClauseInfo *) lfirst(l);		if (bms_equal(ininfo->righthand, rel->relids))		{			sub_targetlist = ininfo->sub_targetlist;			break;		}	}	/*	 * 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 = length(sub_targetlist);	}	else	{		pathnode->rows = rel->rows;		numCols = length(FastListValue(&rel->reltargetlist));	}	/*	 * Estimate cost for sort+unique implementation	 */	cost_sort(&sort_path, root, NIL,			  subpath->total_cost,			  rel->rows,			  rel->width);	/*	 * 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 targetlist for sure	 * (else we can't be sure about the datatypes involved).	 */	pathnode->use_hash = false;	if (enable_hashagg && sub_targetlist && hash_safe_tlist(sub_targetlist))	{		/*		 * Estimate the overhead per hashtable entry at 64 bytes (same as		 * in planner.c).		 */		int			hashentrysize = rel->width + 64;		if (hashentrysize * pathnode->rows <= SortMem * 1024L)		{			cost_agg(&agg_path, root,					 AGG_HASHED, 0,					 numCols, pathnode->rows,					 subpath->startup_cost,					 subpath->total_cost,					 rel->rows);			if (agg_path.total_cost < sort_path.total_cost)				pathnode->use_hash = true;		}	}	if (pathnode->use_hash)	{		pathnode->path.startup_cost = agg_path.startup_cost;		pathnode->path.total_cost = agg_path.total_cost;	}	else	{		pathnode->path.startup_cost = sort_path.startup_cost;		pathnode->path.total_cost = sort_path.total_cost;	}	rel->cheapest_unique_path = (Path *) pathnode;	return pathnode;}/* * hash_safe_tlist - can datatypes of given tlist be hashed? * * We assume hashed aggregation will work if the datatype's equality operator * is marked hashjoinable. * * XXX this probably should be somewhere else.	See also hash_safe_grouping * in plan/planner.c. */static boolhash_safe_tlist(List *tlist){	List	   *tl;	foreach(tl, tlist)	{		Node	   *expr = (Node *) lfirst(tl);		Operator	optup;		bool		oprcanhash;		optup = equality_oper(exprType(expr), true);		if (!optup)			return false;		oprcanhash = ((Form_pg_operator) GETSTRUCT(optup))->oprcanhash;		ReleaseSysCache(optup);		if (!oprcanhash)			return false;	}	return true;}/* * create_subqueryscan_path *	  Creates a path corresponding to a sequential scan of a subquery, *	  returning the pathnode. */Path *create_subqueryscan_path(RelOptInfo *rel, List *pathkeys){	Path	   *pathnode = makeNode(Path);	pathnode->pathtype = T_SubqueryScan;	pathnode->parent = rel;	pathnode->pathkeys = pathkeys;	cost_subqueryscan(pathnode, rel);	return pathnode;}/* * create_functionscan_path *	  Creates a path corresponding to a sequential scan of a function, *	  returning the pathnode. */Path *create_functionscan_path(Query *root, RelOptInfo *rel){	Path	   *pathnode = makeNode(Path);	pathnode->pathtype = T_FunctionScan;	pathnode->parent = rel;	pathnode->pathkeys = NIL;	/* for now, assume unordered result */	cost_functionscan(pathnode, root, rel);	return pathnode;}/* * create_nestloop_path *	  Creates a pathnode corresponding to a nestloop join between two *	  relations. * * 'joinrel' is the join relation. * 'jointype' is the type of join required * 'outer_path' is the outer path * 'inner_path' is the inner path * 'restrict_clauses' are the RestrictInfo nodes to apply at the join * 'pathkeys' are the path keys of the new join path * * Returns the resulting path node. */NestPath *create_nestloop_path(Query *root,					 RelOptInfo *joinrel,					 JoinType jointype,					 Path *outer_path,					 Path *inner_path,					 List *restrict_clauses,					 List *pathkeys){	NestPath   *pathnode = makeNode(NestPath);	pathnode->path.pathtype = T_NestLoop;	pathnode->path.parent = joinrel;	pathnode->jointype = jointype;	pathnode->outerjoinpath = outer_path;	pathnode->innerjoinpath = inner_path;	pathnode->joinrestrictinfo = restrict_clauses;	pathnode->path.pathkeys = pathkeys;	cost_nestloop(pathnode, root);	return pathnode;}/* * create_mergejoin_path *	  Creates a pathnode corresponding to a mergejoin join between *	  two relations * * 'joinrel' is the join relation * 'jointype' is the type of join required * 'outer_path' is the outer path * 'inner_path' is the inner path * 'restrict_clauses' are the RestrictInfo nodes to apply at the join * 'pathkeys' are the path keys of the new join path * 'mergeclauses' are the RestrictInfo nodes to use as merge clauses *		(this should be a subset of the restrict_clauses list) * 'outersortkeys' are the sort varkeys for the outer relation * 'innersortkeys' are the sort varkeys for the inner relation */MergePath *create_mergejoin_path(Query *root,					  RelOptInfo *joinrel,					  JoinType jointype,					  Path *outer_path,					  Path *inner_path,					  List *restrict_clauses,					  List *pathkeys,					  List *mergeclauses,					  List *outersortkeys,					  List *innersortkeys){	MergePath  *pathnode = makeNode(MergePath);	/*	 * If the given paths are already well enough ordered, we can skip	 * doing an explicit sort.	 */	if (outersortkeys &&		pathkeys_contained_in(outersortkeys, outer_path->pathkeys))		outersortkeys = NIL;	if (innersortkeys &&		pathkeys_contained_in(innersortkeys, inner_path->pathkeys))		innersortkeys = NIL;	/*	 * If we are not sorting the inner path, we may need a materialize	 * node to ensure it can be marked/restored.  (Sort does support	 * mark/restore, so no materialize is needed in that case.)	 *	 * Since the inner side must be ordered, and only Sorts and IndexScans	 * can create order to begin with, you might think there's no problem	 * --- but you'd be wrong.  Nestloop and merge joins can *preserve*	 * the order of their inputs, so they can be selected as the input of	 * a mergejoin, and they don't support mark/restore at present.	 */	if (innersortkeys == NIL &&		!ExecSupportsMarkRestore(inner_path->pathtype))		inner_path = (Path *)			create_material_path(inner_path->parent, inner_path);	pathnode->jpath.path.pathtype = T_MergeJoin;	pathnode->jpath.path.parent = joinrel;	pathnode->jpath.jointype = jointype;	pathnode->jpath.outerjoinpath = outer_path;	pathnode->jpath.innerjoinpath = inner_path;	pathnode->jpath.joinrestrictinfo = restrict_clauses;	pathnode->jpath.path.pathkeys = pathkeys;	pathnode->path_mergeclauses = mergeclauses;	pathnode->outersortkeys = outersortkeys;	pathnode->innersortkeys = innersortkeys;	cost_mergejoin(pathnode, root);	return pathnode;}/* * create_hashjoin_path *	  Creates a pathnode corresponding to a hash join between two relations. * * 'joinrel' is the join relation * 'jointype' is the type of join required * 'outer_path' is the cheapest outer path * 'inner_path' is the cheapest inner path * 'restrict_clauses' are the RestrictInfo nodes to apply at the join * 'hashclauses' are the RestrictInfo nodes to use as hash clauses *		(this should be a subset of the restrict_clauses list) */HashPath *create_hashjoin_path(Query *root,					 RelOptInfo *joinrel,					 JoinType jointype,					 Path *outer_path,					 Path *inner_path,					 List *restrict_clauses,					 List *hashclauses){	HashPath   *pathnode = makeNode(HashPath);	pathnode->jpath.path.pathtype = T_HashJoin;	pathnode->jpath.path.parent = joinrel;	pathnode->jpath.jointype = jointype;	pathnode->jpath.outerjoinpath = outer_path;	pathnode->jpath.innerjoinpath = inner_path;	pathnode->jpath.joinrestrictinfo = restrict_clauses;	/* A hashjoin never has pathkeys, since its ordering is unpredictable */	pathnode->jpath.path.pathkeys = NIL;	pathnode->path_hashclauses = hashclauses;	cost_hashjoin(pathnode, root);	return pathnode;}

⌨️ 快捷键说明

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