relnode.c

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

C
614
字号
/*------------------------------------------------------------------------- * * relnode.c *	  Relation-node lookup/construction routines * * 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/util/relnode.c,v 1.89 2008/01/01 19:45:50 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "optimizer/cost.h"#include "optimizer/pathnode.h"#include "optimizer/paths.h"#include "optimizer/plancat.h"#include "optimizer/restrictinfo.h"#include "parser/parsetree.h"#include "utils/hsearch.h"typedef struct JoinHashEntry{	Relids		join_relids;	/* hash key --- MUST BE FIRST */	RelOptInfo *join_rel;} JoinHashEntry;static void build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,					RelOptInfo *input_rel);static List *build_joinrel_restrictlist(PlannerInfo *root,						   RelOptInfo *joinrel,						   RelOptInfo *outer_rel,						   RelOptInfo *inner_rel);static void build_joinrel_joinlist(RelOptInfo *joinrel,					   RelOptInfo *outer_rel,					   RelOptInfo *inner_rel);static List *subbuild_joinrel_restrictlist(RelOptInfo *joinrel,							  List *joininfo_list,							  List *new_restrictlist);static List *subbuild_joinrel_joinlist(RelOptInfo *joinrel,						  List *joininfo_list,						  List *new_joininfo);/* * build_simple_rel *	  Construct a new RelOptInfo for a base relation or 'other' relation. */RelOptInfo *build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind){	RelOptInfo *rel;	RangeTblEntry *rte;	/* Rel should not exist already */	Assert(relid > 0 && relid < root->simple_rel_array_size);	if (root->simple_rel_array[relid] != NULL)		elog(ERROR, "rel %d already exists", relid);	/* Fetch RTE for relation */	rte = root->simple_rte_array[relid];	Assert(rte != NULL);	rel = makeNode(RelOptInfo);	rel->reloptkind = reloptkind;	rel->relids = bms_make_singleton(relid);	rel->rows = 0;	rel->width = 0;	rel->reltargetlist = NIL;	rel->pathlist = NIL;	rel->cheapest_startup_path = NULL;	rel->cheapest_total_path = NULL;	rel->cheapest_unique_path = NULL;	rel->relid = relid;	rel->rtekind = rte->rtekind;	/* min_attr, max_attr, attr_needed, attr_widths are set below */	rel->indexlist = NIL;	rel->pages = 0;	rel->tuples = 0;	rel->subplan = NULL;	rel->subrtable = NIL;	rel->baserestrictinfo = NIL;	rel->baserestrictcost.startup = 0;	rel->baserestrictcost.per_tuple = 0;	rel->joininfo = NIL;	rel->has_eclass_joins = false;	rel->index_outer_relids = NULL;	rel->index_inner_paths = NIL;	/* Check type of rtable entry */	switch (rte->rtekind)	{		case RTE_RELATION:			/* Table --- retrieve statistics from the system catalogs */			get_relation_info(root, rte->relid, rte->inh, rel);			break;		case RTE_SUBQUERY:		case RTE_FUNCTION:		case RTE_VALUES:			/*			 * Subquery, function, or values list --- set up attr range and			 * arrays			 *			 * Note: 0 is included in range to support whole-row Vars			 */			rel->min_attr = 0;			rel->max_attr = list_length(rte->eref->colnames);			rel->attr_needed = (Relids *)				palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids));			rel->attr_widths = (int32 *)				palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));			break;		default:			elog(ERROR, "unrecognized RTE kind: %d",				 (int) rte->rtekind);			break;	}	/* Save the finished struct in the query's simple_rel_array */	root->simple_rel_array[relid] = rel;	/*	 * If this rel is an appendrel parent, recurse to build "other rel"	 * RelOptInfos for its children.  They are "other rels" because they are	 * not in the main join tree, but we will need RelOptInfos to plan access	 * to them.	 */	if (rte->inh)	{		ListCell   *l;		foreach(l, root->append_rel_list)		{			AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);			/* append_rel_list contains all append rels; ignore others */			if (appinfo->parent_relid != relid)				continue;			(void) build_simple_rel(root, appinfo->child_relid,									RELOPT_OTHER_MEMBER_REL);		}	}	return rel;}/* * find_base_rel *	  Find a base or other relation entry, which must already exist. */RelOptInfo *find_base_rel(PlannerInfo *root, int relid){	RelOptInfo *rel;	Assert(relid > 0);	if (relid < root->simple_rel_array_size)	{		rel = root->simple_rel_array[relid];		if (rel)			return rel;	}	elog(ERROR, "no relation entry for relid %d", relid);	return NULL;				/* keep compiler quiet */}/* * build_join_rel_hash *	  Construct the auxiliary hash table for join relations. */static voidbuild_join_rel_hash(PlannerInfo *root){	HTAB	   *hashtab;	HASHCTL		hash_ctl;	ListCell   *l;	/* Create the hash table */	MemSet(&hash_ctl, 0, sizeof(hash_ctl));	hash_ctl.keysize = sizeof(Relids);	hash_ctl.entrysize = sizeof(JoinHashEntry);	hash_ctl.hash = bitmap_hash;	hash_ctl.match = bitmap_match;	hash_ctl.hcxt = CurrentMemoryContext;	hashtab = hash_create("JoinRelHashTable",						  256L,						  &hash_ctl,					HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT);	/* Insert all the already-existing joinrels */	foreach(l, root->join_rel_list)	{		RelOptInfo *rel = (RelOptInfo *) lfirst(l);		JoinHashEntry *hentry;		bool		found;		hentry = (JoinHashEntry *) hash_search(hashtab,											   &(rel->relids),											   HASH_ENTER,											   &found);		Assert(!found);		hentry->join_rel = rel;	}	root->join_rel_hash = hashtab;}/* * find_join_rel *	  Returns relation entry corresponding to 'relids' (a set of RT indexes), *	  or NULL if none exists.  This is for join relations. */RelOptInfo *find_join_rel(PlannerInfo *root, Relids relids){	/*	 * Switch to using hash lookup when list grows "too long".	The threshold	 * is arbitrary and is known only here.	 */	if (!root->join_rel_hash && list_length(root->join_rel_list) > 32)		build_join_rel_hash(root);	/*	 * Use either hashtable lookup or linear search, as appropriate.	 *	 * Note: the seemingly redundant hashkey variable is used to avoid taking	 * the address of relids; unless the compiler is exceedingly smart, doing	 * so would force relids out of a register and thus probably slow down the	 * list-search case.	 */	if (root->join_rel_hash)	{		Relids		hashkey = relids;		JoinHashEntry *hentry;		hentry = (JoinHashEntry *) hash_search(root->join_rel_hash,											   &hashkey,											   HASH_FIND,											   NULL);		if (hentry)			return hentry->join_rel;	}	else	{		ListCell   *l;		foreach(l, root->join_rel_list)		{			RelOptInfo *rel = (RelOptInfo *) lfirst(l);			if (bms_equal(rel->relids, relids))				return rel;		}	}	return NULL;}/* * build_join_rel *	  Returns relation entry corresponding to the union of two given rels, *	  creating a new relation entry if none already exists. * * 'joinrelids' is the Relids set that uniquely identifies the join * 'outer_rel' and 'inner_rel' are relation nodes for the relations to be *		joined * 'jointype': type of join (inner/outer) * 'restrictlist_ptr': result variable.  If not NULL, *restrictlist_ptr *		receives the list of RestrictInfo nodes that apply to this *		particular pair of joinable relations. * * restrictlist_ptr makes the routine's API a little grotty, but it saves * duplicated calculation of the restrictlist... */RelOptInfo *build_join_rel(PlannerInfo *root,			   Relids joinrelids,			   RelOptInfo *outer_rel,			   RelOptInfo *inner_rel,			   JoinType jointype,			   List **restrictlist_ptr){	RelOptInfo *joinrel;	List	   *restrictlist;	/*	 * See if we already have a joinrel for this set of base rels.	 */	joinrel = find_join_rel(root, joinrelids);	if (joinrel)	{		/*		 * Yes, so we only need to figure the restrictlist for this particular		 * pair of component relations.		 */		if (restrictlist_ptr)			*restrictlist_ptr = build_joinrel_restrictlist(root,

⌨️ 快捷键说明

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