⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 joinrels.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
字号:
/*------------------------------------------------------------------------- * * joinrels.c *	  Routines to determine which relations should be joined * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.35.2.1 1999/08/02 06:26:58 scrappy Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "optimizer/cost.h"#include "optimizer/joininfo.h"#include "optimizer/pathnode.h"#include "optimizer/paths.h"#include "optimizer/tlist.h"static List *new_joininfo_list(List *joininfo_list, Relids join_relids);static bool nonoverlap_sets(List *s1, List *s2);static bool is_subset(List *s1, List *s2);static void set_joinrel_size(RelOptInfo *joinrel, RelOptInfo *outer_rel,				 RelOptInfo *inner_rel, JoinInfo *jinfo);static RelOptInfo *make_join_rel(RelOptInfo *outer_rel, RelOptInfo *inner_rel,								 JoinInfo *joininfo);static List *new_join_tlist(List *tlist, int first_resdomno);/* * make_rels_by_joins *	  Find all possible joins for each of the outer join relations in *	  'outer_rels'.  A rel node is created for each possible join relation, *	  and the resulting list of nodes is returned.	If at all possible, only *	  those relations for which join clauses exist are considered.	If none *	  of these exist for a given relation, all remaining possibilities are *	  considered. * * Returns a list of rel nodes corresponding to the new join relations. */List *make_rels_by_joins(Query *root, List *old_rels){	List	   *joined_rels = NIL;	List	   *join_list = NIL;	List	   *r = NIL;	foreach(r, old_rels)	{		RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);		if (!(joined_rels = make_rels_by_clause_joins(root, old_rel,													  old_rel->joininfo,													  NIL)))		{			/*			 * Oops, we have a relation that is not joined to any other			 * relation.  Cartesian product time.			 */			joined_rels = make_rels_by_clauseless_joins(old_rel,													root->base_rel_list);			joined_rels = nconc(joined_rels,								make_rels_by_clauseless_joins(old_rel,															  old_rels));		}		join_list = nconc(join_list, joined_rels);	}	return join_list;}/* * make_rels_by_clause_joins *	  Determines whether joins can be performed between an outer relation *	  'outer_rel' and those relations within 'outer_rel's joininfo nodes *	  (i.e., relations that participate in join clauses that 'outer_rel' *	  participates in).  This is possible if all but one of the relations *	  contained within the join clauses of the joininfo node are already *	  contained within 'outer_rel'. * * 'outer_rel' is the relation entry for the outer relation * 'joininfo_list' is a list of join clauses which 'outer_rel' *		participates in * * Returns a list of new join relations. */List *make_rels_by_clause_joins(Query *root, RelOptInfo *old_rel,						  List *joininfo_list, Relids only_relids){	List	   *join_list = NIL;	List	   *i = NIL;	foreach(i, joininfo_list)	{		JoinInfo   *joininfo = (JoinInfo *) lfirst(i);		RelOptInfo *joined_rel;		Relids		unjoined_relids = joininfo->unjoined_relids;		if (unjoined_relids != NIL)		{			if (length(unjoined_relids) == 1 &&				(only_relids == NIL ||			/* geqo only wants certain relids to make new rels */				 intMember(lfirsti(unjoined_relids), only_relids)))			{				joined_rel = make_join_rel(old_rel,										   get_base_rel(root,											   lfirsti(unjoined_relids)),										   joininfo);				join_list = lappend(join_list, joined_rel);				/* Right-sided plan */				if (length(old_rel->relids) > 1)				{					joined_rel = make_join_rel(							get_base_rel(root, lfirsti(unjoined_relids)),											   old_rel,											   joininfo);					join_list = lappend(join_list, joined_rel);				}			}			if (only_relids == NIL)		/* no bushy from geqo */			{				List	   *r;				foreach(r, root->join_rel_list)				{					RelOptInfo *join_rel = lfirst(r);					Assert(length(join_rel->relids) > 1);					if (is_subset(unjoined_relids, join_rel->relids) &&					  nonoverlap_sets(old_rel->relids, join_rel->relids))					{						joined_rel = make_join_rel(old_rel,												   join_rel,												   joininfo);						join_list = lappend(join_list, joined_rel);					}				}			}		}	}	return join_list;}/* * make_rels_by_clauseless_joins *	  Given an outer relation 'outer_rel' and a list of inner relations *	  'inner_rels', create a join relation between 'outer_rel' and each *	  member of 'inner_rels' that isn't already included in 'outer_rel'. * * Returns a list of new join relations. */List *make_rels_by_clauseless_joins(RelOptInfo *old_rel, List *inner_rels){	RelOptInfo *inner_rel;	List	   *t_list = NIL;	List	   *i = NIL;	foreach(i, inner_rels)	{		inner_rel = (RelOptInfo *) lfirst(i);		if (nonoverlap_sets(inner_rel->relids, old_rel->relids))		{			t_list = lappend(t_list,							 make_join_rel(old_rel,										   inner_rel,										   (JoinInfo *) NULL));		}	}	return t_list;}/* * make_join_rel *	  Creates and initializes a new join relation. * * 'outer_rel' and 'inner_rel' are relation nodes for the relations to be *		joined * 'joininfo' is the joininfo node(join clause) containing both *		'outer_rel' and 'inner_rel', if any exists * * Returns the new join relation node. */static RelOptInfo *make_join_rel(RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinInfo *joininfo){	RelOptInfo *joinrel = makeNode(RelOptInfo);	List	   *joinrel_joininfo_list = NIL;	List	   *new_outer_tlist;	List	   *new_inner_tlist;	/*	 * Create a new tlist by removing irrelevant elements from both tlists	 * of the outer and inner join relations and then merging the results	 * together.	 */	new_outer_tlist = new_join_tlist(outer_rel->targetlist, 1);	new_inner_tlist = new_join_tlist(inner_rel->targetlist,									 length(new_outer_tlist) + 1);	joinrel->relids = NIL;	joinrel->indexed = false;	joinrel->pages = 0;	joinrel->tuples = 0;	joinrel->width = 0;/*	joinrel->targetlist = NIL;*/	joinrel->pathlist = NIL;	joinrel->cheapestpath = (Path *) NULL;	joinrel->pruneable = true;	joinrel->classlist = NULL;	joinrel->relam = InvalidOid;	joinrel->ordering = NULL;	joinrel->restrictinfo = NIL;	joinrel->joininfo = NULL;	joinrel->innerjoin = NIL;	/*	 * This function uses a trick to pass inner/outer rels as different	 * lists, and then flattens it out later.  bjm	 */	joinrel->relids = lcons(outer_rel->relids, lcons(inner_rel->relids, NIL));	new_outer_tlist = nconc(new_outer_tlist, new_inner_tlist);	joinrel->targetlist = new_outer_tlist;	if (joininfo)		joinrel->restrictinfo = joininfo->jinfo_restrictinfo;	joinrel_joininfo_list = new_joininfo_list(								   nconc(copyObject(outer_rel->joininfo),										 copyObject(inner_rel->joininfo)),									   nconc(listCopy(outer_rel->relids),										   listCopy(inner_rel->relids)));	joinrel->joininfo = joinrel_joininfo_list;	set_joinrel_size(joinrel, outer_rel, inner_rel, joininfo);	return joinrel;}/* * new_join_tlist *	  Builds a join relations's target list by keeping those elements that *	  will be in the final target list and any other elements that are still *	  needed for future joins.	For a target list entry to still be needed *	  for future joins, its 'joinlist' field must not be empty after removal *	  of all relids in 'other_relids'. * * 'tlist' is the target list of one of the join relations * 'other_relids' is a list of relids contained within the other *				join relation * 'first_resdomno' is the resdom number to use for the first created *				target list entry * * Returns the new target list. */static List *new_join_tlist(List *tlist,			   int first_resdomno){	int			resdomno = first_resdomno - 1;	TargetEntry *xtl = NULL;	List	   *t_list = NIL;	List	   *i = NIL;	List	   *join_list = NIL;	bool		in_final_tlist = false;	foreach(i, tlist)	{		xtl = lfirst(i);		/*		 * XXX surely this is wrong?  join_list is never changed?  tgl		 * 2/99		 */		in_final_tlist = (join_list == NIL);		if (in_final_tlist)		{			resdomno += 1;			t_list = lappend(t_list, create_tl_element(get_expr(xtl), resdomno));		}	}	return t_list;}/* * new_joininfo_list *	  Builds a join relation's joininfo list by checking for join clauses *	  which still need to used in future joins involving this relation.  A *	  join clause is still needed if there are still relations in the clause *	  not contained in the list of relations comprising this join relation. *	  New joininfo nodes are only created and added to *	  'current_joininfo_list' if a node for a particular join hasn't already *	  been created. * * 'current_joininfo_list' contains a list of those joininfo nodes that *		have already been built * 'joininfo_list' is the list of join clauses involving this relation * 'join_relids' is a list of relids corresponding to the relations *		currently being joined * * Returns a list of joininfo nodes, new and old. */static List *new_joininfo_list(List *joininfo_list, Relids join_relids){	List	   *current_joininfo_list = NIL;	Relids		new_unjoined_relids = NIL;	JoinInfo   *other_joininfo = (JoinInfo *) NULL;	List	   *xjoininfo = NIL;	foreach(xjoininfo, joininfo_list)	{		List	   *or;		JoinInfo   *joininfo = (JoinInfo *) lfirst(xjoininfo);		new_unjoined_relids = joininfo->unjoined_relids;		foreach(or, new_unjoined_relids)		{			if (intMember(lfirsti(or), join_relids))				new_unjoined_relids = lremove((void *) lfirst(or), new_unjoined_relids);		}		joininfo->unjoined_relids = new_unjoined_relids;		if (new_unjoined_relids != NIL)		{			other_joininfo = joininfo_member(new_unjoined_relids,											 current_joininfo_list);			if (other_joininfo)			{				other_joininfo->jinfo_restrictinfo = (List *)					LispUnion(joininfo->jinfo_restrictinfo,							  other_joininfo->jinfo_restrictinfo);			}			else			{				other_joininfo = makeNode(JoinInfo);				other_joininfo->unjoined_relids = joininfo->unjoined_relids;				other_joininfo->jinfo_restrictinfo = joininfo->jinfo_restrictinfo;				other_joininfo->mergejoinable = joininfo->mergejoinable;				other_joininfo->hashjoinable = joininfo->hashjoinable;				current_joininfo_list = lcons(other_joininfo,											  current_joininfo_list);			}		}	}	return current_joininfo_list;}/* * get_cheapest_complete_rel *	   Find the join relation that includes all the original *	   relations, i.e. the final join result. * * 'join_rel_list' is a list of join relations. * * Returns the list of final join relations. */RelOptInfo *get_cheapest_complete_rel(List *join_rel_list){	List	   *xrel = NIL;	RelOptInfo *final_rel = NULL;	/*	 * find the relations that have no further joins, i.e., its joininfos	 * all have unjoined_relids nil.	 */	foreach(xrel, join_rel_list)	{		RelOptInfo *rel = (RelOptInfo *) lfirst(xrel);		List	   *xjoininfo = NIL;		bool		final = true;		foreach(xjoininfo, rel->joininfo)		{			JoinInfo   *joininfo = (JoinInfo *) lfirst(xjoininfo);			if (joininfo->unjoined_relids != NIL)			{				final = false;				break;			}		}		if (final)			if (final_rel == NULL ||			 path_is_cheaper(rel->cheapestpath, final_rel->cheapestpath))				final_rel = rel;	}	return final_rel;}static boolnonoverlap_sets(List *s1, List *s2){	List	   *x = NIL;	foreach(x, s1)	{		int			e = lfirsti(x);		if (intMember(e, s2))			return false;	}	return true;}static boolis_subset(List *s1, List *s2){	List	   *x = NIL;	foreach(x, s1)	{		int			e = lfirsti(x);		if (!intMember(e, s2))			return false;	}	return true;}static voidset_joinrel_size(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinInfo *jinfo){	int			ntuples;	float		selec;	/*	 * voodoo magic. but better than a size of 0. I have no idea why we	 * didn't set the size before. -ay 2/95	 */	if (jinfo == NULL)	{		/* worst case: the cartesian product */		ntuples = outer_rel->tuples * inner_rel->tuples;	}	else	{		selec = product_selec(jinfo->jinfo_restrictinfo);/*		ntuples = Min(outer_rel->tuples,inner_rel->tuples) * selec; */		ntuples = outer_rel->tuples * inner_rel->tuples * selec;	}	/*	 * I bet sizes less than 1 will screw up optimization so make the best	 * case 1 instead of 0	- jolly	 */	if (ntuples < 1)		ntuples = 1;	joinrel->tuples = ntuples;}

⌨️ 快捷键说明

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