mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Nab some low-hanging fruit: replace the planner's base_rel_list and
other_rel_list with a single array indexed by rangetable index. This reduces find_base_rel from O(N) to O(1) without any real penalty. While find_base_rel isn't one of the major bottlenecks in any profile I've seen so far, it was starting to creep up on the radar screen for complex queries --- so might as well fix it.
This commit is contained in:
		@@ -8,7 +8,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.253 2005/06/05 22:32:54 tgl Exp $
 | 
					 *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.254 2005/06/06 04:13:35 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * NOTES
 | 
					 * NOTES
 | 
				
			||||||
 *	  Every node type that can appear in stored rules' parsetrees *must*
 | 
					 *	  Every node type that can appear in stored rules' parsetrees *must*
 | 
				
			||||||
@@ -1150,9 +1150,8 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	WRITE_NODE_TYPE("PLANNERINFO");
 | 
						WRITE_NODE_TYPE("PLANNERINFO");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* NB: this isn't a complete set of fields */
 | 
				
			||||||
	WRITE_NODE_FIELD(parse);
 | 
						WRITE_NODE_FIELD(parse);
 | 
				
			||||||
	WRITE_NODE_FIELD(base_rel_list);
 | 
					 | 
				
			||||||
	WRITE_NODE_FIELD(other_rel_list);
 | 
					 | 
				
			||||||
	WRITE_NODE_FIELD(join_rel_list);
 | 
						WRITE_NODE_FIELD(join_rel_list);
 | 
				
			||||||
	WRITE_NODE_FIELD(equi_key_list);
 | 
						WRITE_NODE_FIELD(equi_key_list);
 | 
				
			||||||
	WRITE_NODE_FIELD(in_info_list);
 | 
						WRITE_NODE_FIELD(in_info_list);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.131 2005/06/05 22:32:55 tgl Exp $
 | 
					 *	  $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.132 2005/06/06 04:13:35 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -88,9 +88,33 @@ make_one_rel(PlannerInfo *root)
 | 
				
			|||||||
	rel = make_fromexpr_rel(root, root->parse->jointree);
 | 
						rel = make_fromexpr_rel(root, root->parse->jointree);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The result should join all the query's base rels.
 | 
						 * The result should join all and only the query's base rels.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	Assert(bms_num_members(rel->relids) == list_length(root->base_rel_list));
 | 
					#ifdef USE_ASSERT_CHECKING
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								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;
 | 
						return rel;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -104,16 +128,29 @@ make_one_rel(PlannerInfo *root)
 | 
				
			|||||||
static void
 | 
					static void
 | 
				
			||||||
set_base_rel_pathlists(PlannerInfo *root)
 | 
					set_base_rel_pathlists(PlannerInfo *root)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ListCell   *l;
 | 
						Index		rti;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	foreach(l, root->base_rel_list)
 | 
						/*
 | 
				
			||||||
 | 
						 * Note: because we call expand_inherited_rtentry inside the loop,
 | 
				
			||||||
 | 
						 * it's quite possible for the base_rel_array to be enlarged while
 | 
				
			||||||
 | 
						 * the loop runs.  Hence don't try to optimize the loop.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						for (rti = 1; rti < root->base_rel_array_size; rti++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		RelOptInfo *rel = (RelOptInfo *) lfirst(l);
 | 
							RelOptInfo *rel = root->base_rel_array[rti];
 | 
				
			||||||
		Index		rti = rel->relid;
 | 
					 | 
				
			||||||
		RangeTblEntry *rte;
 | 
							RangeTblEntry *rte;
 | 
				
			||||||
		List	   *inheritlist;
 | 
							List	   *inheritlist;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Assert(rti > 0);		/* better be base rel */
 | 
							/* 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rte = rt_fetch(rti, root->parse->rtable);
 | 
							rte = rt_fetch(rti, root->parse->rtable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (rel->rtekind == RTE_SUBQUERY)
 | 
							if (rel->rtekind == RTE_SUBQUERY)
 | 
				
			||||||
@@ -246,10 +283,9 @@ set_inherited_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 | 
				
			|||||||
		childOID = childrte->relid;
 | 
							childOID = childrte->relid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Make a RelOptInfo for the child so we can do planning.  Do NOT
 | 
							 * Make a RelOptInfo for the child so we can do planning.
 | 
				
			||||||
		 * attach the RelOptInfo to the query's base_rel_list, however,
 | 
							 * Mark it as an "other rel" since it will not be part of the
 | 
				
			||||||
		 * since the child is not part of the main join tree.  Instead,
 | 
							 * main join tree.
 | 
				
			||||||
		 * the child RelOptInfo is added to other_rel_list.
 | 
					 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		childrel = build_other_rel(root, childRTindex);
 | 
							childrel = build_other_rel(root, childRTindex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.82 2005/06/05 22:32:56 tgl Exp $
 | 
					 *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.83 2005/06/06 04:13:35 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -106,12 +106,15 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction,
 | 
				
			|||||||
							  &constant_quals);
 | 
												  &constant_quals);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * init planner lists to empty
 | 
						 * Init planner lists to empty.  We create the base_rel_array with a
 | 
				
			||||||
 | 
						 * size that will be sufficient if no pullups or inheritance additions
 | 
				
			||||||
 | 
						 * happen ... otherwise it will be enlarged as needed.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * NOTE: in_info_list was set up by subquery_planner, do not touch here
 | 
						 * NOTE: in_info_list was set up by subquery_planner, do not touch here
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	root->base_rel_list = NIL;
 | 
						root->base_rel_array_size = list_length(parse->rtable) + 1;
 | 
				
			||||||
	root->other_rel_list = NIL;
 | 
						root->base_rel_array = (RelOptInfo **)
 | 
				
			||||||
 | 
							palloc0(root->base_rel_array_size * sizeof(RelOptInfo *));
 | 
				
			||||||
	root->join_rel_list = NIL;
 | 
						root->join_rel_list = NIL;
 | 
				
			||||||
	root->equi_key_list = NIL;
 | 
						root->equi_key_list = NIL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.67 2005/06/05 22:32:56 tgl Exp $
 | 
					 *	  $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.68 2005/06/06 04:13:36 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -25,7 +25,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static RelOptInfo *make_reloptinfo(PlannerInfo *root, int relid,
 | 
					static RelOptInfo *make_reloptinfo(PlannerInfo *root, int relid,
 | 
				
			||||||
								   RelOptKind reloptkind);
 | 
													   RelOptKind reloptkind);
 | 
				
			||||||
static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel);
 | 
					static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
 | 
				
			||||||
 | 
													RelOptInfo *input_rel);
 | 
				
			||||||
static List *build_joinrel_restrictlist(PlannerInfo *root,
 | 
					static List *build_joinrel_restrictlist(PlannerInfo *root,
 | 
				
			||||||
						   RelOptInfo *joinrel,
 | 
											   RelOptInfo *joinrel,
 | 
				
			||||||
						   RelOptInfo *outer_rel,
 | 
											   RelOptInfo *outer_rel,
 | 
				
			||||||
@@ -43,78 +44,60 @@ static void subbuild_joinrel_joinlist(RelOptInfo *joinrel,
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * build_base_rel
 | 
					 * build_base_rel
 | 
				
			||||||
 *	  Construct a new base relation RelOptInfo, and put it in the query's
 | 
					 *	  Construct a new base relation RelOptInfo, and put it in the query's
 | 
				
			||||||
 *	  base_rel_list.
 | 
					 *	  base_rel_array.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
build_base_rel(PlannerInfo *root, int relid)
 | 
					build_base_rel(PlannerInfo *root, int relid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ListCell   *l;
 | 
						Assert(relid > 0);
 | 
				
			||||||
	RelOptInfo *rel;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Rel should not exist already */
 | 
						/* Rel should not exist already */
 | 
				
			||||||
	foreach(l, root->base_rel_list)
 | 
						if (relid < root->base_rel_array_size &&
 | 
				
			||||||
	{
 | 
							root->base_rel_array[relid] != NULL)
 | 
				
			||||||
		rel = (RelOptInfo *) lfirst(l);
 | 
							elog(ERROR, "rel already exists");
 | 
				
			||||||
		if (relid == rel->relid)
 | 
					 | 
				
			||||||
			elog(ERROR, "rel already exists");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* It should not exist as an "other" rel, either */
 | 
					 | 
				
			||||||
	foreach(l, root->other_rel_list)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		rel = (RelOptInfo *) lfirst(l);
 | 
					 | 
				
			||||||
		if (relid == rel->relid)
 | 
					 | 
				
			||||||
			elog(ERROR, "rel already exists as \"other\" rel");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* No existing RelOptInfo for this base rel, so make a new one */
 | 
						/* No existing RelOptInfo for this base rel, so make a new one */
 | 
				
			||||||
	rel = make_reloptinfo(root, relid, RELOPT_BASEREL);
 | 
						(void) make_reloptinfo(root, relid, RELOPT_BASEREL);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* and add it to the list */
 | 
					 | 
				
			||||||
	root->base_rel_list = lcons(rel, root->base_rel_list);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * build_other_rel
 | 
					 * build_other_rel
 | 
				
			||||||
 *	  Returns relation entry corresponding to 'relid', creating a new one
 | 
					 *	  Returns relation entry corresponding to 'relid', creating a new one
 | 
				
			||||||
 *	  if necessary.  This is for 'other' relations, which are much like
 | 
					 *	  if necessary.  This is for 'other' relations, which are much like
 | 
				
			||||||
 *	  base relations except that they live in a different list.
 | 
					 *	  base relations except that they have a different RelOptKind.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
RelOptInfo *
 | 
					RelOptInfo *
 | 
				
			||||||
build_other_rel(PlannerInfo *root, int relid)
 | 
					build_other_rel(PlannerInfo *root, int relid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ListCell   *l;
 | 
					 | 
				
			||||||
	RelOptInfo *rel;
 | 
						RelOptInfo *rel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Already made? */
 | 
						Assert(relid > 0);
 | 
				
			||||||
	foreach(l, root->other_rel_list)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		rel = (RelOptInfo *) lfirst(l);
 | 
					 | 
				
			||||||
		if (relid == rel->relid)
 | 
					 | 
				
			||||||
			return rel;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* It should not exist as a base rel */
 | 
						/* Already made? */
 | 
				
			||||||
	foreach(l, root->base_rel_list)
 | 
						if (relid < root->base_rel_array_size)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		rel = (RelOptInfo *) lfirst(l);
 | 
							rel = root->base_rel_array[relid];
 | 
				
			||||||
		if (relid == rel->relid)
 | 
							if (rel)
 | 
				
			||||||
			elog(ERROR, "rel already exists as base rel");
 | 
							{
 | 
				
			||||||
 | 
								/* it should not exist as a base rel */
 | 
				
			||||||
 | 
								if (rel->reloptkind == RELOPT_BASEREL)
 | 
				
			||||||
 | 
									elog(ERROR, "rel already exists as base rel");
 | 
				
			||||||
 | 
								/* otherwise, A-OK */
 | 
				
			||||||
 | 
								return rel;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* No existing RelOptInfo for this other rel, so make a new one */
 | 
						/* No existing RelOptInfo for this other rel, so make a new one */
 | 
				
			||||||
	/* presently, must be an inheritance child rel */
 | 
						/* presently, must be an inheritance child rel */
 | 
				
			||||||
	rel = make_reloptinfo(root, relid, RELOPT_OTHER_CHILD_REL);
 | 
						rel = make_reloptinfo(root, relid, RELOPT_OTHER_CHILD_REL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* and add it to the list */
 | 
					 | 
				
			||||||
	root->other_rel_list = lcons(rel, root->other_rel_list);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return rel;
 | 
						return rel;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * make_reloptinfo
 | 
					 * make_reloptinfo
 | 
				
			||||||
 *	  Construct a RelOptInfo for the specified rangetable index.
 | 
					 *	  Construct a RelOptInfo for the specified rangetable index,
 | 
				
			||||||
 | 
					 *	  and enter it into base_rel_array.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Common code for build_base_rel and build_other_rel.
 | 
					 * Common code for build_base_rel and build_other_rel.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -172,31 +155,40 @@ make_reloptinfo(PlannerInfo *root, int relid, RelOptKind reloptkind)
 | 
				
			|||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Add the finished struct to the base_rel_array */
 | 
				
			||||||
 | 
						if (relid >= root->base_rel_array_size)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int		oldsize = root->base_rel_array_size;
 | 
				
			||||||
 | 
							int		newsize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							newsize = Max(oldsize * 2, relid + 1);
 | 
				
			||||||
 | 
							root->base_rel_array = (RelOptInfo **)
 | 
				
			||||||
 | 
								repalloc(root->base_rel_array, newsize * sizeof(RelOptInfo *));
 | 
				
			||||||
 | 
							MemSet(root->base_rel_array + oldsize, 0,
 | 
				
			||||||
 | 
								   (newsize - oldsize) * sizeof(RelOptInfo *));
 | 
				
			||||||
 | 
							root->base_rel_array_size = newsize;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						root->base_rel_array[relid] = rel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rel;
 | 
						return rel;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * find_base_rel
 | 
					 * find_base_rel
 | 
				
			||||||
 *	  Find a base or other relation entry, which must already exist
 | 
					 *	  Find a base or other relation entry, which must already exist.
 | 
				
			||||||
 *	  (since we'd have no idea which list to add it to).
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
RelOptInfo *
 | 
					RelOptInfo *
 | 
				
			||||||
find_base_rel(PlannerInfo *root, int relid)
 | 
					find_base_rel(PlannerInfo *root, int relid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ListCell   *l;
 | 
					 | 
				
			||||||
	RelOptInfo *rel;
 | 
						RelOptInfo *rel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	foreach(l, root->base_rel_list)
 | 
						Assert(relid > 0);
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		rel = (RelOptInfo *) lfirst(l);
 | 
					 | 
				
			||||||
		if (relid == rel->relid)
 | 
					 | 
				
			||||||
			return rel;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	foreach(l, root->other_rel_list)
 | 
						if (relid < root->base_rel_array_size)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		rel = (RelOptInfo *) lfirst(l);
 | 
							rel = root->base_rel_array[relid];
 | 
				
			||||||
		if (relid == rel->relid)
 | 
							if (rel)
 | 
				
			||||||
			return rel;
 | 
								return rel;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -308,8 +300,13 @@ build_join_rel(PlannerInfo *root,
 | 
				
			|||||||
	 * Create a new tlist containing just the vars that need to be output
 | 
						 * Create a new tlist containing just the vars that need to be output
 | 
				
			||||||
	 * from this join (ie, are needed for higher joinclauses or final
 | 
						 * from this join (ie, are needed for higher joinclauses or final
 | 
				
			||||||
	 * output).
 | 
						 * output).
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * NOTE: the tlist order for a join rel will depend on which pair of
 | 
				
			||||||
 | 
						 * outer and inner rels we first try to build it from.  But the
 | 
				
			||||||
 | 
						 * contents should be the same regardless.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	build_joinrel_tlist(root, joinrel);
 | 
						build_joinrel_tlist(root, joinrel, outer_rel);
 | 
				
			||||||
 | 
						build_joinrel_tlist(root, joinrel, inner_rel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Construct restrict and join clause lists for the new joinrel. (The
 | 
						 * Construct restrict and join clause lists for the new joinrel. (The
 | 
				
			||||||
@@ -344,48 +341,39 @@ build_join_rel(PlannerInfo *root,
 | 
				
			|||||||
 *	  Builds a join relation's target list.
 | 
					 *	  Builds a join relation's target list.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The join's targetlist includes all Vars of its member relations that
 | 
					 * The join's targetlist includes all Vars of its member relations that
 | 
				
			||||||
 * will still be needed above the join.
 | 
					 * will still be needed above the join.  This subroutine adds all such
 | 
				
			||||||
 *
 | 
					 * Vars from the specified input rel's tlist to the join rel's tlist.
 | 
				
			||||||
 * In a former lifetime, this just merged the tlists of the two member
 | 
					 | 
				
			||||||
 * relations first presented.  While we could still do that, working from
 | 
					 | 
				
			||||||
 * lists of Vars would mean doing a find_base_rel lookup for each Var.
 | 
					 | 
				
			||||||
 * It seems more efficient to scan the list of base rels and collect the
 | 
					 | 
				
			||||||
 * needed vars directly from there.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * We also compute the expected width of the join's output, making use
 | 
					 * We also compute the expected width of the join's output, making use
 | 
				
			||||||
 * of data that was cached at the baserel level by set_rel_width().
 | 
					 * of data that was cached at the baserel level by set_rel_width().
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel)
 | 
					build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
 | 
				
			||||||
 | 
										RelOptInfo *input_rel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Relids		relids = joinrel->relids;
 | 
						Relids		relids = joinrel->relids;
 | 
				
			||||||
	ListCell   *rels;
 | 
						ListCell   *vars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	joinrel->reltargetlist = NIL;
 | 
						foreach(vars, input_rel->reltargetlist)
 | 
				
			||||||
	joinrel->width = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	foreach(rels, root->base_rel_list)
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		RelOptInfo *baserel = (RelOptInfo *) lfirst(rels);
 | 
							Var		   *var = (Var *) lfirst(vars);
 | 
				
			||||||
		ListCell   *vars;
 | 
							RelOptInfo *baserel;
 | 
				
			||||||
 | 
							int			ndx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!bms_is_member(baserel->relid, relids))
 | 
							/* We can't run into any child RowExprs here */
 | 
				
			||||||
			continue;
 | 
							Assert(IsA(var, Var));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		foreach(vars, baserel->reltargetlist)
 | 
							/* Get the Var's original base rel */
 | 
				
			||||||
 | 
							baserel = find_base_rel(root, var->varno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Is it still needed above this joinrel? */
 | 
				
			||||||
 | 
							ndx = var->varattno - baserel->min_attr;
 | 
				
			||||||
 | 
							if (bms_nonempty_difference(baserel->attr_needed[ndx], relids))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Var		   *var = (Var *) lfirst(vars);
 | 
								/* Yup, add it to the output */
 | 
				
			||||||
			int			ndx = var->varattno - baserel->min_attr;
 | 
								joinrel->reltargetlist = lappend(joinrel->reltargetlist, var);
 | 
				
			||||||
 | 
								Assert(baserel->attr_widths[ndx] > 0);
 | 
				
			||||||
			/* We can't run into any child RowExprs here */
 | 
								joinrel->width += baserel->attr_widths[ndx];
 | 
				
			||||||
			Assert(IsA(var, Var));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (bms_nonempty_difference(baserel->attr_needed[ndx], relids))
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				joinrel->reltargetlist = lappend(joinrel->reltargetlist, var);
 | 
					 | 
				
			||||||
				Assert(baserel->attr_widths[ndx] > 0);
 | 
					 | 
				
			||||||
				joinrel->width += baserel->attr_widths[ndx];
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 | 
					 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 | 
				
			||||||
 * Portions Copyright (c) 1994, Regents of the University of California
 | 
					 * Portions Copyright (c) 1994, Regents of the University of California
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.110 2005/06/05 22:32:57 tgl Exp $
 | 
					 * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.111 2005/06/06 04:13:36 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -24,7 +24,6 @@
 | 
				
			|||||||
 * Relids
 | 
					 * Relids
 | 
				
			||||||
 *		Set of relation identifiers (indexes into the rangetable).
 | 
					 *		Set of relation identifiers (indexes into the rangetable).
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef Bitmapset *Relids;
 | 
					typedef Bitmapset *Relids;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -63,8 +62,16 @@ typedef struct PlannerInfo
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	Query	   *parse;			/* the Query being planned */
 | 
						Query	   *parse;			/* the Query being planned */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	List	   *base_rel_list;	/* list of base-relation RelOptInfos */
 | 
						/*
 | 
				
			||||||
	List	   *other_rel_list; /* list of other 1-relation RelOptInfos */
 | 
						 * base_rel_array holds pointers to "base rels" and "other rels" (see
 | 
				
			||||||
 | 
						 * comments for RelOptInfo for more info).  It is indexed by rangetable
 | 
				
			||||||
 | 
						 * index (so entry 0 is always wasted).  Entries can be NULL when
 | 
				
			||||||
 | 
						 * an RTE does not correspond to a base relation.  Note that the array
 | 
				
			||||||
 | 
						 * may be enlarged on-the-fly.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct RelOptInfo **base_rel_array;	/* All one-relation RelOptInfos */
 | 
				
			||||||
 | 
						int			base_rel_array_size;	/* current allocated array len */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	List	   *join_rel_list;	/* list of join-relation RelOptInfos */
 | 
						List	   *join_rel_list;	/* list of join-relation RelOptInfos */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	List	   *equi_key_list;	/* list of lists of equijoined
 | 
						List	   *equi_key_list;	/* list of lists of equijoined
 | 
				
			||||||
@@ -90,15 +97,15 @@ typedef struct PlannerInfo
 | 
				
			|||||||
 * is the joining of two or more base rels.  A joinrel is identified by
 | 
					 * is the joining of two or more base rels.  A joinrel is identified by
 | 
				
			||||||
 * the set of RT indexes for its component baserels.  We create RelOptInfo
 | 
					 * the set of RT indexes for its component baserels.  We create RelOptInfo
 | 
				
			||||||
 * nodes for each baserel and joinrel, and store them in the PlannerInfo's
 | 
					 * nodes for each baserel and joinrel, and store them in the PlannerInfo's
 | 
				
			||||||
 * base_rel_list and join_rel_list respectively.
 | 
					 * base_rel_array and join_rel_list respectively.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Note that there is only one joinrel for any given set of component
 | 
					 * Note that there is only one joinrel for any given set of component
 | 
				
			||||||
 * baserels, no matter what order we assemble them in; so an unordered
 | 
					 * baserels, no matter what order we assemble them in; so an unordered
 | 
				
			||||||
 * set is the right datatype to identify it with.
 | 
					 * set is the right datatype to identify it with.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * We also have "other rels", which are like base rels in that they refer to
 | 
					 * We also have "other rels", which are like base rels in that they refer to
 | 
				
			||||||
 * single RT indexes; but they are not part of the join tree, and are stored
 | 
					 * single RT indexes; but they are not part of the join tree, and are given
 | 
				
			||||||
 * in other_rel_list not base_rel_list.
 | 
					 * a different RelOptKind to identify them.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Currently the only kind of otherrels are those made for child relations
 | 
					 * Currently the only kind of otherrels are those made for child relations
 | 
				
			||||||
 * of an inheritance scan (SELECT FROM foo*).  The parent table's RTE and
 | 
					 * of an inheritance scan (SELECT FROM foo*).  The parent table's RTE and
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user